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).
Related
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
};
I recently wrote about the function of class member function callbacks. I need to save the callback object and function pointer, then call the function pointer and fill in the appropriate parameters where the callback is needed.
I started out as a form of typedef void (AAA::*Function)(int a, int b);, but when I need to support different parameter lists of member function, I obviously need a dynamic way to implement it.
class AAA
{
public:
int add(int a, int b)
{
return (a + b);
}
};
class BBB
{
public:
void setValue(std::string value)
{
this->value = value;
}
private:
std::string value;
};
class CCC
{
public:
void bind(??? p) // Binding objects and callback functions.
{
this->p = p;
}
template <class... Args>
auto callback(Args&&... args) // Autofill parameter list.
{
return this->p(std::forward<Args>(args)...);
}
private:
??? p; // How is this function pointer implemented?
};
int main()
{
AAA aaa;
BBB bbb;
CCC ccc;
ccc.bind(???(aaa, &AAA::add));
int number = ccc.callback(5, 6);
ccc.bind(???(bbb, &BBB::setValue));
ccc.callback("Hello");
system("pause");
return 0;
}
I don't know how can I implement the function pointer "???".
You basically are asking to have fully dynamicly typed and checked function calls.
To have fully dynamic function calls, you basically have to throw out the C++ function call system.
This is a bad idea, but I'll tell you how to do it.
A dynamicly callable object looks roughly like this:
using dynamic_function = std::function< std::any( std::vector<std::any> ) >
where use use
struct nothing_t {};
when we want to return void.
Then you write machinery that takes an object and a specific signature, and wraps it up.
template<class R, class...Args, class F>
struct dynamic_function_maker {
template<std::size_t...Is>
dynamic_function operator()(std::index_sequence<Is...>, F&& f)const {
return [f=std::forward<F>(f)](std::vector<std::any> args)->std::any {
if (sizeof...(Is) != args.size())
throw std::invalid_argument("Wrong number of arguments");
if constexpr( std::is_same< std::invoke_result_t<F const&, Args... >, void >{} )
{
f( std::any_cast<Args>(args[Is])... );
return nothing_t{};
}
else
{
return f( std::any_cast<Args>(args[Is])... );
}
};
}
dynamic_function operator()(F&& f)const {
return (*this)(std::make_index_sequence<sizeof...(Args)>{}, std::forward<F>(f));
}
};
template<class R, class...Args, class F>
dynamic_function make_dynamic_function(F f){
return dynamic_function_maker<R,Args...,F>{}(std::forward<F>(f));
}
next you'll want to deduce signatures of function pointers and the like:
template<class R, class...Args>
dynamic_function make_dynamic_function(R(*f)(Args...)){
return dynamic_function_maker<R,Args...,F>{}(std::forward<F>(f));
}
template<class Tclass R, class...Args>
dynamic_function make_dynamic_function(T* t, R(T::*f)(Args...)){
return dynamic_function_maker<R,Args...,F>{}(
[t,f](auto&&...args)->decltype(auto){return (t->*f)(decltype(args)(args)...);}
);
}
then after fixing typos above you should be able to solve your original problem.
Again, as someone who can actually write and understand the above code, I strongly advise you not to use it. It is fragile and dangerous.
There is almost never a good reason to store callbacks in places where you don't know what the arguments you are going to call it with.
There should be a different type and instance of CCC for each set of arguments you want to call it with. 99/100 times when people ask this question, they are asking the wrong question.
C++ is a type-safe language. This means that you cannot do exactly what you've outlined in your question. A pointer to a function that takes specific parameters is a different type from a pointer to a function that takes different parameters. This is fundamental to C++.
std::bind can be use to type-erase different types to the same type, but you get a single type at the end, that can be called only with a matching set of parameters (if any). It is not possible to invoke the "underlying" bound function, with its real parameters. That's because the whole purpose of std::bind is to make them disappear, and inaccessible. That's what std::bind is for.
You only have a limited set options to make this work while staying with the bounds and constraints of C++'s type-safety.
Make use of a void *, in some fashion. Actually, don't. Don't do that. That will just cause more problems, and headache.
Have a separate list and classes of callbacks, one list for each set of callbacks that take a specific set of parameters. You must know, at the point of invoking a callback, what parameters you intend to pass. So, just get your callback from the appropriate list.
Make use of std::variant. The type-safe std::variant is C++17 only (but boost has a similar template that's mostly equivalent, and available with older C++ revisions). All your callbacks take a single std::variant parameter, a variant of every possible set of parameters (designated as a std::tuple of them, or some class/struct instance). Each callback will have to decide what to do if it receives a std::variant containing the wrong parameter value.
Alternatively, the std::variant can be a variant of different std::function types, thus shifting the responsibility of type-checking to the caller, instead of each callback.
The bottom line is that C++ is fundamentally a type-safe language; and this is precisely one of the reasons why one would choose to use C++ instead of a different language that does not have the same kind of type-safety.
But being a type-safe language, that means that you have certain limitations when it comes to juggling different types together. Specifically: you can't. Everything in C++ is always, and must be, a single type.
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.
edit This is not a duplicate of Undefined reference to static class member. That question explored the cause of the problem (which I explain below). Here, I'm looking for a different solution from those proposed in the answers to that questions (which implied changing the declaration/definition of the constexpr variable to be used -- essentially by adding a definition in a compilation unit).
I have created a little variadic template function make_string() to generate a std::string from any number of io-able arguments as follows.
using std::ostringstream; // just for this example
inline ostringstream&write(ostringstream&ostr, const char*x)
{ if(x) ostr<<x; return ostr; }
template<class T>
inline ostringstream&write(ostringstream&ostr, T const&x)
{ ostr<<x; return ostr; }
inline ostringstream&write(ostringstream&ostr) noexcept
{ return ostr; }
template<class T, class... R>
inline ostringstream&write(ostringstream&ostr, T const&x, R&&... r)
{ return write(write(ostr,x), std::forward<R>(r)...); }
inline std::string make_string(const char*text)
{ return {text?text:""}; }
inline std::string make_string(std::string const&text)
{ return {text}; }
template<typename T>
inline auto make_string(T var) -> decltype(std::to_string(var))
{ return std::to_string(var); }
template<class... Args>
inline std::string make_string(Args&&... args)
{
ostringstream ostr;
write(ostr,std::forward<Args>(args)...);
return std::move(ostr.str());
}
Now, this works pretty well and can be used like this
throw std::runtime_error(make_string("offset=",offset," > max_offset =",
max_offset"));
However, there is a problem when printing static constexpr class members, as in
class foo
{
static constexpr int max_offset=some_value;
// ...
void bar(int offset)
{
if(offset > max_offset)
throw std::runtime_error(make_string("offset=",offset," > max_offset=",
max_offset"));
}
};
This causes an error at link time. The reason is that make_string takes all its arguments by reference, including the static constexpr max_offset. As a result, a reference to foo::max_offset will be required at linking, see also.
How can I avoid this problem without abandoning the idea of make_string()? (Perhaps one could replace the variadic template with a variadic macro, but I would consider this as some sort of regression.) There must be a way for make_string to take its arguments by value or reference, depending on type (so that builtin types can be taken by value). How?
I'm not sure whether the compiler is correct in getting it's knickers in a bunch jimmies rustled with a ref to constexpr here.
However, you could perhaps find your way out using boost's
call_traits<T>::param_type
Defines a type that represents the "best" way to pass a parameter of type T to a function.
(see http://www.boost.org/doc/libs/1_55_0/libs/utility/call_traits.htm).
First, I am not sure why you need so much code for make_string. I'd simply define it as
template<class... Args>
inline std::string make_string(Args&&... args)
{
ostringstream ostr;
_do{ostr << std::forward<Args>(args)...};
return std::move(ostr.str());
}
where
struct _do { template <typename... T> _do(T&&...) { } };
is a helper struct that lets you evaluate expressions in the right order (but watch out, GCC incorrectly evaluates right-to-left until 4.9 at least).
Now, to your question. As I said in my comment, I feel your problem is irrelevant to make_string. In Undefined reference to static class member, in my question passing a static constexpr variable by universal reference?, and in all relevant questions I've seen, the suggested answer is that one defines the variable somewhere out of class:
constexpr int foo::max_offset;
I'm not sure if this is a problem for you. It is a problem for me because in heavily templated code it implies too much duplication (see discussion below my question). Anyhow, if it is a problem, I see a few other simple solutions to ensure call-by-value:
use make_string(..., int(max_offset)) instead of make_string(..., max_offset)
as a shortcut, +max_offset does the same job (suggested here)
define static constexpr int max_offset() { return some_value; }, then use max_offset() instead of max_offset throughout
let some part of code (function or template) deduce max_offset as a non-type int template parameter, then use it directly
lastly, define make_string(Args... args) (this is the simplest but does not apply here as you don't want to copy all those strings)
I am not discussing use of make_string in throwing an exception; this is a different problem.
I want to implement a "Task" class, which can store a function pointer along with some arguments to pass to it. like std::bind(). and I have some question about how to store the arguments.
class BaseTask {
public:
virtual ~BaseTask() {}
virtual void run() = 0;
};
template<typename ... MTArg>
class Task : public BaseTask {
public:
typedef void (*RawFunction)(MTArg...);
Task(RawFunction rawFunction, MTArg&& ... args) : // Q1: MTArg&& ... args
rawFunction(rawFunction),
args(std::make_tuple(std::forward<MTArg>(args)...)) {} // Q2: std::make_tuple(std::forward<MTArg>(args)...)
virtual void run() {
callFunction(GenIndexSequence<sizeof...(MTArg)>()); // struct GenIndexSequence<count> : IndexSequence<0, ..., count-1>
}
private:
template<unsigned int... argIndexs>
inline void callFunction() {
rawFunction(std::forward<MTArg>(std::get<argIndexs>(args))...);
}
private:
RawFunction rawFunction;
std::tuple<MTArg...> args; // Q3: std::tuple<MTArg...>
};
Q1: is && after MTArg necessary
Q2: is this way correct to init args
Q3: is type of args correct, do I need:
std::tuple<special_decay_t<MTArg>...>
according to this: http://en.cppreference.com/w/cpp/utility/tuple/make_tuple
// end of questions
I want Task can be used in this way:
void fun(int i, const int& j) {}
BaseTask* createTask1() {
return new Task<int, const int&>(&fun, 1, 2); // "2" must not be disposed at the time of task.run(), so inside Task "2" should be store as "int", not "const int&"
}
BaseTask* createTask2(const int& i, const int& j) {
return new Task<int, const int&>(&fun, i, j); // "j" must not be disposed at the time of task.run(), so inside Task "j" should be store as "int", not "const int&"
}
void test(){
createTask1()->run();
createTask2(1, 2)->run();
}
task will only be run no more then once, that is zero or one times.
You aren't allowed to use std::tuple::special_decay_t even if it exists: it is an implementation detail. That code on cppreference exists for exposition only: it works "as if" that type exists. If your implementation uses that code, that is an implementation detail that different compilers will not have, and the next iteration of your compiler is free to change/make private/rename/etc.
As exposition, it explains what you need to write if you want to repeat the special decay process of std::make_tuple and a few other C++11 interfaces.
As a first step, I'll keep your overall design, and repair it a touch. Then I'll point out an alternative.
MTArg... are the parameters of the function:
template<typename ... MTArg>
struct Task {
typedef void (*RawFunction)(MTArg...);
Here we want to forward some set of arguments into a tuple, but the arguments need not match MTArg -- they just have to be convertible:
template<typename ... Args>
explicit Task(RawFunction rawFunction, Args&&... args)
rawFunction(rawFunction),
args(std::make_tuple(std::forward<Args>(args)...)) {}
which the above checks. Note I made it explicit, as if Args... is empty, we don't want this to be a converting constructor.
void run() {
callFunction(GenIndexSequence<sizeof...(MTArg)>());
}
private:
template<unsigned int... argIndexs>
inline void callFunction() {
rawFunction(std::forward<MTArg>(std::get<argIndexs>(args))...);
}
RawFunction rawFunction;
std::tuple<MTArg...> args;
};
and then we write a make_task function:
template<typename ... MTArg, typename... Args>
Task<MTArg...> make_task( void(*raw)(MTArg...), Args...&& args ) {
return { raw, std::forward<Args>(args)... };
}
which looks something like that. Note that we deduce MTArg... from the function pointer, and Args... from the arguments.
Just because our function takes foo by value, does not mean we should make copies of it, or store an rvalue reference to it, or what have you.
Now, the above disagrees with how std::function and std::thread work, which is where special_decay_t comes in.
Usually when you store arguments to a function, you want to store actual copies, not references to possibly local variables or temporary variables that may go away. And if your function takes arguments by lvalue non-const reference, you want to take extra care at the call site that you aren't binding it to stack variables.
That is where reference_wrapper comes in and the special_decay_t bit: deduced arguments are decayed into literals, which have conventional lifetimes. Types packaged into std::reference_wrapper are turned into references, which lets you pass references through the interface.
I'd be tempted to duplicate the C++11 pattern, but force creators of a Task to explicitly reference_wrapper all types that are supposed to be passed by reference into the raw function.
But I am unsure, and the code to do that gets a touch messy.
Q1: is && after MTArg necessary
Task(RawFunction rawFunction, MTArg&& ... args) : // Q1: MTArg&& ... args
No, it is not necessary, since it is a concrete function (constructor in this case). It would matter if it was a template function, then args would be of universal reference type.
For the same reason, you do not need to use std::foward.
Q3: is type of args correct, do I need:
std::tuple<special_decay_t<MTArg>...>
Yes, because types should not be rvalues, if you want to store them in a tupple.