Auto is not allowed here for lambda class in header file - c++

I'm using c++14, auto is working fine on .cpp file, however when i try to create generic lambda in my class it generates error "Auto is not allowed here"
What did i do wrong?
Code:
class MyClass{
private:
// Works
std::function<void(MyClass&)> assign = [&](MyClass& other){
//do something
};
// Does not work
std::function<void(auto)> assign = [&](auto other){
//do something
};
// Does not work
auto assign = [&](auto other){
//do something
};
};

Your two attempts fail for different reasons. Let's look at the second one first:
auto assign = [&](auto other){
//do something
};
This could work in theory: the lambda expression has a definite type that could be deduced and used. However, as addressed in this Q&A (for C++11 but still relevant), the language simply does not allow auto member variables, so that's that.
Your first attempt fails for a more design-related reason. Well, the immediate issue is that void(auto) is not a valid type (auto is a syntactic keyword with tailored semantics, not a type), but one could conceivably use some tag types to make std::function<void(auto_t)> a valid specialization.
The issue, however, is that std::function is a type-erasure tool: its goal is to take in and conceal a functionoid (such as your lambda), then call it on demand. By the time the call is made, the functionoid's type is not known anymore, much less its potential operator() template -- handling the general case would require instantiating that template at runtime for a yet-unknown argument type, which is not possible.
Bottom line: storing the lambda is conceptually valid but its type deduction is not supported, and type erasure is the wrong tool for the job since templates are involved. Your only solution is to create an explicit functor class, and use that as a member:
class MyClass {
struct {
template <class T>
void operator()(T other) const {
// do something
}
} assign;
};
Bonus point: C++20 allows lambdas in unevaluated context and default-constructible lambdas, which means that the following insanity is now valid 🙃
class MyClass {
decltype([](auto other) {
// do something
}) assign;
};

These statements are perfectly ok on a different context / scope:
void myfunc() {
auto lambda = []() { }; // works fine
}
But the here you refer is a class definition, where there can't be members without explicit types.
class MyClass {
std::function<void(MyClass&)> assign = lambda;
// works, because there exists now a variable assign,
// of specific type, which is initialised from a lambda
auto kOne = 1; // fails for the same reason
};

Related

C++ How to conditionally initialize a template class object?

I have a template class
template <typename T>
class myClass
{
T variable;
....
};
I want to create an object of myClass , depending of some condition the object should either hold a string or int . how do I conditionally initialize like below :
if (condition1)
myClass<userDefinedType1> x;
else
myClass<userDefinedType2> x;
I don't think the code I wrote above is possible , but the problem is whether the type should be userDefinedType1 or userDefinedType2 is not known to me at compile time . How can I initialize the template class object when the type will only be known to me at run time based on user inputs ?
If the type of the problem isn't known until runtime, then your options are limited.
If the number of possible instantiations is small/simple and you are using c++17 or above, one option is to just use std::variant:
using MyClass = std::variant<std::monostate, myClass<userDefinedType1>,myClass<userDefinedType2>>;
auto v = MyClass{}; // create one without a value to start
if (condition) {
v = myClass<userDefinedType1>{};
} else {
v = myClass<userDefinedType2>{};
}
std::variant takes care of ensuring incorrect access does not occur (which prevents strict-aliasing violations), and it also will ensure that non-trivial destructors get invoked for the correctly instantiated types. This can then be used easily with visit assuming the functions that need to be called are homogeneously defined, since you can use a lambda with an auto parameter which will choose the correct type:
std::visit([](auto& cls){
cls.do_something();
}, v);
One other utility that can be used is std::any, for a similar purpose:
auto v = std::any{};
if (condition) {
v = myClass<userDefinedType1>{};
} else {
v = myClass<userDefinedType2>{};
}
The downside with std::any is that accessing the internal types is much more complicated and needs to be polled with std::any_cast. Still doable, but not so nice
Alternative, polymorphism is an option if your template might have some base-class that you can erase to. This may not work for every design, but in the case that it does you can simply use a std::unique_ptr to hold an instance to the base while you construct the class.
class myClassBase {
...
virtual auto common_api(...) -> void = 0;
...
};
template <typename T>
class myClass : public myClassBase {
...
auto common_api(...) -> void override { ... }
...
};
...
auto v = std::unique_ptr<Base>{};
if (condition) {
v = std::make_unique<myClass<userDefinedType1>>(...);
} else {
v = std::make_unique<myClass<userDefinedType2>>(...);
}
The last real option is to perform some form of manual type-erasure, where you create a wrapper class that erases the template argument. This solution is not generic and will be highly-specific to the class itself for how it can be erased. This may involve something as simple as a polymorphic wrapper that erases the type in the implementation, or it can be more complex such as bound function-pointers that do more work.
Ah, the crazy world of template metaprogramming (TMP). It's a lot easier now due to constexpr etc. but for programming the members of a class you still need to go old-school.
You have to generate your member by inheriting it from a base class.
That base class can be a template, including a fancy conditional TMP construct. You can see this in some of the standard library classes.
Hmm, you want the same data member (x), just having a different type. Well, that's easier: Make it of type T2. That can be generated using template stuff. Something like this:
using T2 = std::conditional_t<condition1, userDefinedType1, userDefinedType2>;
myClass<T2> x;
not known to me at compile time .
Well, that's another story. You can't change the generated code except at compile time.
Do you want a variable x that can hold either of two types?
That can use Object Oriented techniques of having a common polymorphic base class with different derived types.
Or, you can use a std::variant.
A (primitive) union as Ozger's answer shows is basically a low-level unchecked version of the same idea. In older versions of C++ such a union could not hold types that had constructors and destructors, but now they can, though you take on a lot of low-level effort. It's basically the language back-end to make writing variant simpler.
You can use a union.
union U {
myClass<userDefinedType1> a;
myClass<userDefinedType2> b;
};
U u;
if (condition1)
u.a = myClass<userDefinedType1>();
else
u.b = myClass<userDefinedType2>();
As stated in the comments, this compiles only if myClass has a trivial destructor, including the implicit destructor that will destruct T in myClass.
Unless you need to store x for future usage,
you can make the code which applies to x template too, and then you branch looks like:
template <typename T> void foo(T);
// ...
if (condition1) {
myClass<userDefinedType1> x;
foo(x);
} else {
myClass<userDefinedType2> x;
foo(x);
}
You can even move x in the function template, so code would be:
template <typename T> void bar(T)
{
myClass<T> x;
// ...
}
// ...
if (condition1) {
bar<userDefinedType1>();
} else {
bar<userDefinedType2>();
}
If you need to store x for future usage, you need either to use std::variant, polymorphism base class or type erasure.
Can't we just make class object dynamically. Something like this:
if (condition1)
myClass<userDefinedType1>* x = new myclass<userDefined1>;
else
myClass<userDefinedType2>* x = new myclass<userDefined2>;
Please let me know what's wrong with this approach

Can concepts restrict the type member variables?

I'm using C++20 & I'm wondering if Concepts is at all possible to solve a situation like this.
Let's say I have a function:
template <typename F>
void doSomething(F f) {
f();
}
doSomething accepts a callable objects (technically lambdas but shouldn't matter I think) & I want to ensure that no member variables of F have a type T. For example, I want:
BadType t;
int x = ...;
double y = ...;
doSomething([t = kj::mv(t), x, y] { ... }); // I want a compile error
doSomething([x, y] { ... }); // No error.
Similarly, I want to validate the arguments of the callable in a similar way:
doSomething([x, y](BadType t) { ... }); // I want a compile error
doSomething([x, y](std::vector<int> c) { ... }); // No compile error
I don't know if this complicates things, but technically BadType itself is a templated type (I want to disable all instances regardless of the template value).
An acceptable answer could be one that provides an example, but I'm also happy with good tutorials that someone feels I should be could be able to cobble together to accomplish. I'm very experienced with C++ & template meta-programming, but concepts feel like a totally alien thing at the moment. Of course, if this isn't possible, then happy to accept such an answer too.
This feels like something that the Reflection TS would be perfect for, but alas clang doesn't have this in an accessible way even in v13 (& I think similarly the GCC work is in a non-mainline branch still). I've explored various static reflection libraries for C++17, but they all suffer from needing to modify the type, which isn't possible here since I'm introspecting a lambda (and BadType is a type defined in a 3p library although that shouldn't matter).
I suspect the answer must be no since each lambda I pass in will have an arbitrary set of names for the variables that get captured & the only examples I've seen of concepts trying to enforce the type of a member variable require a single known variable name, but maybe this is an interesting challenge for someone who's a Concepts master.
You can easily check if a simple struct/aggregate T contains any field with type TType using boost::pfr:
#include <boost/pfr.hpp>
template <typename TType, typename T>
[[nodiscard]] constexpr bool has_any_data_member_of_type() noexcept
{
return []<std::size_t... Is>(std::index_sequence<Is...>)
{
return (std::is_same_v<boost::pfr::tuple_element_t<Is, T>, TType> || ...);
}(std::make_index_sequence<boost::pfr::tuple_size_v<T>>{});
}
struct a { int i; float f; char c; };
struct b { int i; char c; };
static_assert( has_any_data_member_of_type<float, a>());
static_assert(!has_any_data_member_of_type<float, b>());
live example on godbolt.org
You can then easily define a concept for that:
template <typename T, typename TType>
concept having_any_data_member_of_type = has_any_data_member_of_type<TType, T>();
Unfortunately, since lambda expressions are not aggregates, you won't be able to use them with has_any_data_member_of_type. However, custom callable objects work:
struct my_callable
{
float f;
float operator()() { return f; }
};
void f0(having_any_data_member_of_type<float> auto f)
{
(void) f();
}
int main()
{
f0(my_callable{}); // OK
}
If you are happy with checking only a direct nesting of an object inside a simple struct/aggregates see Vittorio's answer.
If your goal is to prohibit capturing an object of some type inside callable objects (for example, prohibiting capturing a reference in the asynchronous callback or prohibiting capturing some object that should not be accessed from callback) then it is impossible in the general case even with reflection TS.
Simple counter example:
BadType t;
doSomething([t = std::any(kj::mv(t))]{...}); // Even reflection TS could not do anything with this.
Another one:
struct Fun {
std::any v;
void operator()() {
....
}
}
Fun f = ...
doSomething(std::move(f)); // Event more powerful reflection than reflection TS (reflection with statements reflection) could not do anything with this.
Even if nesting in multiple layers of objects could be taken into account any kind of type-erasure simply could not.

Is it safe to `std::move(*this)` into an object being created from `this->some_method`?

I am trying to build a chain of callable objects that can be later executed asynchronously. I wanted to try out the following approach: build a "nested" structure of nodes (by moving each node into its "parent") resulting in an object that stores all the computations and can be start the chain on demand.
This is what I had in mind:
template <typename TParent, typename TF>
struct node
{
TParent _parent;
TF _f;
node(TParent&& parent, TF&& f)
: _parent{std::move(parent)}, _f{std::move(f)}
{
}
template <typename TFContinuation>
auto then(TFContinuation&& f_continuation)
{
using this_type = node<TParent, TF>;
return node<this_type, std::decay_t<TFContinuation>>
{std::move(*this), std::move(f_continuation)};
// ^^^^^^^^^^^^^^^^
// ...safe?
}
};
The code above would allow the user to write chains like the following one:
int main()
{
node n{some_root_callable, []{/*...*/}};
n.then([]{/*...*/})
.then([]{/*...*/})
.then([]{/*...*/})
.then([]{/*...*/});
}
(The real implementation would support more useful abstraction such as when_all(...) or when_any(...).)
Wandbox example.
Assuming that TParent, TF, and TFContinuation are movable callable objects, is it safe (i.e. well-defined) to call std::move(*this) during the invocation of node::then?
You can do that and it's safe. It will only leaves members in an undefined but valid state in most cases. With that said, it is safe to move this, as long as you don't try to use its members again. But with standard library types and most user defined types, this won't even be a problem.
There is one thing that I would change. I would only allow call from rvalue this:
template <typename TFContinuation> // v-- notice the && here.
auto then(TFContinuation&& f_continuation) && {
using this_type = node<TParent, TF>;
return node<this_type, std::decay_t<TFContinuation>>{
std::move(*this), std::move(f_continuation)
};
}
The great this is you can even overload it when it's not an rvalue:
template <typename TFContinuation>
auto then(TFContinuation&& f_continuation) const & {
using this_type = node<TParent, TF>;
return node<this_type, std::decay_t<TFContinuation>>{
*this, std::move(f_continuation)
};
}
Whether there's a problem in that code depends on what that code does with the reference that it gets. If the called code turns the object into mush, then when it returns, your code has to deal with an object that's been turned into mush. But that's true of any function that you call from a member function, regardless of whether its called with an rvalue reference, a modifiable lvalue reference, a pointer, or any other mechanism you might want to imagine.

C++11 std::forward a pointer

I have a Signal class in my application that provides classes with an option to expose events (same as in .NET).
The class works and all is well.
Yesterday I saw this SO question (and its answer) and was familiarized with std::forward.
I decided to try to use it in my code so I changed every std::function<void(Args...)> to std::function<void(Args&&...)> and in the raise function (the operator()) I used the same logic I saw in the above link so now the function takes Args&&...args and the callback uses std::forward<Args>(args)...
Here's a simplified version of my Signal class (with some changes to make it a good example):
template<typename... Args> class Signal
{
public:
int operator+=(const std::function<void(Args&&...)>& func) {
int token = getNewToken();
m_subscribers.emplace(token, func);
return token;
}
void operator()(Args&&... args) {
for (auto it : m_subscribers) {
it.second(std::forward<Args>(args)...);
}
}
private:
std::map<int, std::function<void(Args&&...)>> m_subscribers;
};
int main() {
int* six = new int(6);
int seven = 7;
Signal<int*> e1;
e1 += [](int* x) { std::cout << *x; };
Signal<int> e2;
e2 += [](int x) { std::cout << x; };
e1(&seven);
e2(6);
e1(six); //Error C2664 'void Signal<int *>::operator ()(int *&&)':
// cannot convert argument 1 from 'int *' to 'int *&&'
e1(std::move(six)); //This is a workaround
return 0;
}
The issue I'm seeing is with classes (or main in this example) that try to raise events with pointers and I'm not sure how to solve this.
My main goal is to have the Signal class a general API and if the developers chose to use Signal<int*> I don't want him\her to raise with std::move.
What am I doing wrong here?
T&& is only a universal reference if T is a non-cv-qualified function template parameter. In your call operator:
void operator()(Args&&... args) {
Args isn't a template parameter of the function, it's a template parameter of the class. So for Signal<int*>, this operator() takes an rvalue reference to int*. Since six is an lvalue, that fails.
What you want is to provide the correct reference qualifications to Signal. Like so:
template<typename... Args>
class Signal
{
using F = std::function<void(Args...)>; // NB: Just Args...
public:
int operator+=(F func) {
int token = getNewToken();
m_subscribers.emplace(token, std::move(func));
return token;
}
void operator()(Args... args) { // NB: just Args...
for (auto& it : m_subscribers) { // NB: auto&
it.second(args...);
}
}
private:
std::map<int, F> m_subscribers;
};
Note that forwarding Args... is questionable anyway. What if you had two subscribers? Once you forward the args once you can't really use them a second time.
The above will make Signal<int*> do what you expect. The operator() will just take an int*, which you can pass either an lvalue or an rvalue to.
Barry's answer is correct, but perhaps not as clearly explained as it could be.
&& is only given its special treatment as a forwarding (or "universal") reference when template parameter deduction occurs. But there is no deduction occurring here:
Signal<int*> e1; // `Args...` is explicitly `int*`
...
e1(six); // `Args...` *has already been specified*
When template classes are instantiated, they are essentially transformed into normal classes that just happen to be written by the compiler. See this answer for an example of what this might look like if written out in C++ code.
In C++14, there is no way to trigger template-parameter deduction of class templates without an auxiliary function (not a constructor):
template <typename Args...>
Signal<Args...> make_signal(Args&&...) { return Signal<Args...>; }
....But note that in your case, this makes no sense: you don't want to infer the types of your arguments when create the Signal, you want to specify them in advance.
(Note that in C++17, there will be support for template argument deduction of class templates. I assume this means that it will be possible to forward template-class arguments, though it's not immediately clear to me what the implications of doing such a thing would be.)
What you want to permit is for arguments to be forwarded at call time. This is actually reasonably simple:
template<typename... Args> class Signal
{
public:
// .... skipping some code...
template <typename... CallArgs>
void operator()(CallArgs&&... args) {
callback(std::forward<CallArgs>(args)...);
}
};
....But, again, in your case this doesn't quite make sense, as noted in Barry's answer. You don't want to forward arguments if you have multiple callbacks, to prevent moving and re-using them.
It's possible to work around this by checking the size of m_subscribers and only using the forwarding code if it's 1, and just passing the arguments as-is otherwise. However, this might lead to confusing behavior, since the way callbacks are invoked shouldn't generally depend on the state of your Signal object. So you could perhaps write a separate class, SingletonSignal, for callbacks that must be invoked with forwarded arguments (e.g. in case a callback wants to transfer ownership of an uncopyable object such as unique_ptr).

Using auto and decltype in C++11

I'm trying to learn the currently accepted features of c++11 and I'm having trouble with auto and decltype. As a learning exercise I'm extending the std class list with some generic functions.
template<class _Ty, class _Ax = allocator<_Ty>>
class FList : public std::list<_Ty, _Ax>
{
public:
void iter(const function<void (_Ty)>& f)
{
for_each(begin(), end(), f);
}
auto map(const function<float (_Ty)>& f) -> FList<float>*
{
auto temp = new FList<float>();
for (auto i = begin(); i != end(); i++)
temp->push_back(f(*i));
return temp;
}
};
auto *ints = new FList<int>();
ints->push_back(2);
ints->iter([](int i) { cout << i; });
auto *floats = ints->map([](int i) { return (float)i; });
floats->iter([](float i) { cout << i; });
For the member map I want the return type to be generic depending on what the passed function returns. So for the return type I could do something like this.
auto map(const function<float (_Ty)>& f) -> FList<decltype(f(_Ty))>*
This would also need to remove the float type in the function template.
auto map(const function<auto (_Ty)>& f) -> FList<decltype(f(_Ty))>*
I could use a template class but that makes the use of instances more verbose since i have to specify the return type.
template<class T> FList<T>* map(const function<T (_Ty)>& f)
To sum of my question i'm trying to figure out how to define map without using a template class and still have it generic in the type it returns.
Deriving from std::list or other std:: containers is discouraged.
Write your operations as free functions so they can work on any standard container via iterators.
Do you mean "define map without using a template function"?
You should be able to use the result_type member type of std::function to get the type it returns.
Also it's not necessary for you to specify that the function is passed as a std::function. You could leave it open as any type, and let the compiler join everything up. You only need std::function for runtime polymorphism.
And using new to create raw heap-allocation objects and returning them by pointer is soooo 1992! :)
Your iter function is essentially the same thing as the range-based for loop.
But all that aside... do you mean something like this?
template <class TFunc>
auto map(const TFunc &f) -> FList<decltype(f(_Ty()))>*
{
auto temp = new FList<decltype(f(_Ty()))>();
for (auto i = begin(); i != end(); i++)
temp->push_back(f(*i));
return temp;
}
This will match anything callable, and will figure out the return type of the function by using decltype.
Note that it requires _Ty to be default constructable. You can get around that by manufacturing an instance:
template <class T>
T make_instance();
No implementation is required because no code is generated that calls it, so the linker has nothing to complain about (thanks to dribeas for pointing this out!)
So the code now becomes:
FList<decltype(f(make_instance<_Ty>()))>*
Or, literally, a list of whatever the type would be you'd get from calling the function f with a reference to an instance of _Ty.
And as a free bonus for accepting, look up rvalue references - these will mean that you can write:
std::list<C> make_list_somehow()
{
std::list<C> result;
// blah...
return result;
}
And then call it like this:
std::list<C> l(make_list_somehow());
Because std::list will have a "move constructor" (like a copy constructor but chosen when the argument is a temporary, like here), it can steal the contents of the return value, i.e. do the same as an optimal swap. So there's no copying of the whole list. (This is why C++0x will make naively-written existing code run faster - many popular but ugly performance tricks will become obsolete).
And you can get the same kind of thing for free for ANY existing class of your own, without having to write a correct move constructor, by using unique_ptr.
std::unique_ptr<MyThing> myThing(make_my_thing_somehow());
You can't use auto in function arguments where you want the types of the arguments to be deduced. You use templates for that. Have a look at:
http://thenewcpp.wordpress.com/2011/10/18/the-keyword-auto/ and
http://thenewcpp.wordpress.com/2011/10/25/decltype-and-declval/. They both explain how to use auto and decltype. They should give you enough information about how they are used. In particular, another answer about make_instance could be done better with declval.
I think the point that Jarrah was making in his answer is that those points do explain exactly how to use these things. I will point out the details anyway:
You can't do this, there are two things wrong:
auto map(const function<auto (_Ty)>& f) -> FList<decltype(f(_Ty))>*
auto can't be used for function arguments. If you want the type of the function to be deduced then you should use templates. The second is that decltype takes an expression, whereas _Ty is a type. Here is how to solve it:
template <typename Ret>
auto
map(const function<Ret (_Ty)>& f)
-> FList<decltype(f(declval<_Ty>()))>
{}
That way there is no magic to create an instance of a type.