This is a followup question to my previous question.
#include <functional>
int foo(void) {return 2;}
class bar {
public:
int operator() (void) {return 3;};
int something(int a) {return a;};
};
template <class C> auto func(C&& c) -> decltype(c()) { return c(); }
template <class C> int doit(C&& c) { return c();}
template <class C> void func_wrapper(C&& c) { func( std::bind(doit<C>, std::forward<C>(c)) ); }
int main(int argc, char* argv[])
{
// call with a function pointer
func(foo);
func_wrapper(foo); // error
// call with a member function
bar b;
func(b);
func_wrapper(b);
// call with a bind expression
func(std::bind(&bar::something, b, 42));
func_wrapper(std::bind(&bar::something, b, 42)); // error
// call with a lambda expression
func( [](void)->int {return 42;} );
func_wrapper( [](void)->int {return 42;} );
return 0;
}
I'm getting a compile errors deep in the C++ headers:
functional:1137: error: invalid initialization of reference of type ‘int (&)()’ from expression of type ‘int (*)()’
functional:1137: error: conversion from ‘int’ to non-scalar type ‘std::_Bind<std::_Mem_fn<int (bar::*)(int)>(bar, int)>’ requested
func_wrapper(foo) is supposed to execute func(doit(foo)). In the real code it packages the function for a thread to execute. func would the function executed by the other thread, doit sits in between to check for unhandled exceptions and to clean up. But the additional bind in func_wrapper messes things up...
At the beginning, please let me introduce 2 key points:
a: When using nested std::bind, the inner std::bind is evaluated first, and the return value will be substituted in its place while the outer std::bind is evaluated. That means std::bind(f, std::bind(g, _1))(x) executes as same as f(g(x)) does. The inner std::bind is supposed to be wrapped by std::ref if the outer std::bind wants a functor rather than a return value.
b: The r-value reference cannot be correctly forwarded to the function by using std::bind. And the reason has already been illustrated in detail.
So, let's look at the question. The most importance function here might be func_wrapper which is intended to perform 3 purposes:
Perfect forwarding a functor to doit function template at first,
then using std::bind to make doit as a closure,
and letting func function template execute the functor returned by std::bind at last.
According to point b, purpose 1 cannot be fulfilled. So, let's forget perfect forwarding and doit function template has to accept a l-value reference parameter.
According to point a, purpose 2 will be performed by using std::ref.
As a result, the final version might be:
#include <functional>
int foo(void) {return 2;}
class bar {
public:
int operator() (void) {return 3;};
int something(int a) {return a;};
};
template <class C> auto func(C&& c) -> decltype(c()) { return c(); }
template <class C> int doit(C&/*&*/ c) // r-value reference can't be forwarded via std::bind
{
return c();
}
template <class C> void func_wrapper(C&& c)
{
func(std::bind(doit<C>,
/* std::forward<C>(c) */ // forget pefect forwarding while using std::bind
std::ref(c)) // try to pass the functor itsself instead of its return value
);
}
int main(int argc, char* argv[])
{
// call with a function pointer
func(foo);
func_wrapper(foo); // error disappears
// call with a member function
bar b;
func(b);
func_wrapper(b);
// call with a bind expression
func(std::bind(&bar::something, b, 42));
func_wrapper(std::bind(&bar::something, b, 42)); // error disappears
// call with a lambda expression
func( [](void)->int {return 42;} );
func_wrapper( [](void)->int {return 42;} );
return 0;
}
But, if you really want to achieve purpose 1 and 2, how? Try this:
#include <functional>
#include <iostream>
void foo()
{
}
struct bar {
void operator()() {}
void dosomething() {}
};
static bar b;
template <typename Executor>
void run(Executor&& e)
{
std::cout << "r-value reference forwarded\n";
e();
}
template <typename Executor>
void run(Executor& e)
{
std::cout << "l-value reference forwarded\n";
e();
}
template <typename Executor>
auto func(Executor&& e) -> decltype(e())
{
return e();
}
template <bool b>
struct dispatcher_traits {
enum { value = b };
};
template <typename Executor, bool is_lvalue_reference>
class dispatcher {
private:
static void dispatch(Executor& e, dispatcher_traits<true>)
{
run(e);
}
static void dispatch(Executor& e, dispatcher_traits<false>)
{
run(std::ref(e));
}
public:
static void forward(Executor& e)
{
dispatch(e, dispatcher_traits<is_lvalue_reference>());
}
};
template <typename Executor>
void func_wrapper(Executor&& e)
{
typedef dispatcher<Executor,
std::is_lvalue_reference<Executor>::value>
dispatcher_type;
func(std::bind(&dispatcher_type::forward, std::ref(e)));
}
int main()
{
func_wrapper(foo); // l-value
func_wrapper(b); // l-value
func_wrapper(bar()); // r-value
func_wrapper(std::bind(&bar::dosomething, &b)); // r-value
func_wrapper([](){}); // r-value
}
Let me explain some points:
To reduce lots of return statements, changing functor signature from int() to void().
The 2 run() function templates are used to check whether the original functor parameter is perfect forwarded or not.
dispatcher_traits is going to map bool constant to type.
You'd better name dispatcher::forward to differ from dispatcher::dispatch or you have to invoke std::bind template with dispatcher::forward's signature.
Looking at this the second time now, and I think I have a plausable explanation for the first error you are seeing.
In this case, it's more helpful to look at the complete error and the template instantiations that lead up to it. The error printed by my compiler (GCC 4.4), for example, ends with the following lines:
test.cpp:12: instantiated from ‘decltype (c()) func(C&&) [with C = std::_Bind<int (*(int (*)()))(int (&)())>]’
test.cpp:16: instantiated from ‘void func_wrapper(C&&) [with C = int (&)()]’
test.cpp:22: instantiated from here
/usr/include/c++/4.4/tr1_impl/functional:1137: error: invalid initialization of reference of type ‘int (&)()’ from expression of type ‘int (*)()’
Now looking at this bottom-up, the actual error message seems correct; the types the compiler has deduced are incompatible.
The first template instantiation, at func_wrapper, clearly shows what type the compiler has deduced from the actual parameter foo in func_wrapper(foo). I personally expected this to be a function pointer, but it is in fact a function reference.
The second template instantiation is hardly readable. But messing around with std::bind a bit, I learned that the format of the textual representation GCC prints for a bind functor is roughly:
std::_Bind<RETURN-TYPE (*(BOUND-VALUE-TYPES))(TARGET-PARAMETER-TYPES)>
So tearing it apart:
std::_Bind<int (*(int (*)()))(int (&)())>
// Return type: int
// Bound value types: int (*)()
// Target parameter types: int (&)()
This is where the incompatible types start. Apparently, even though c in func_wrapper is a function reference, it turns into a function pointer once passed to std::bind, resulting in the type incompatibility. For what it's worth, std::forward doesn't matter at all in this case.
My reasoning here is that std::bind only seems to care about values, and not references. In C/C++, there's no such thing as a function value; there's only references and pointers. So when the function reference is dereferenced, the compiler can only meaningfully give you a function pointer.
The only control you have over this is your template parameters. You will have to tell the compiler that you're dealing with a function pointer from the start to make this work. It's probably what you had in mind anyways. To do that, explicitly specify the type you want for the template parameter C:
func_wrapper<int (*)()>(foo);
Or the more brief solution, explicitly take the function's address:
func_wrapper(&foo); // with C = int (*)()
I'll get back to you if I ever figure out the second error. :)
Related
I am trying to pass function as template argument to a function in a class, but there is some mistake. The code is giving an error error: missing template arguments before 'obj'. How can I fix this so that it compiles?
#include<iostream>
double sum_fun(const double &a, const double &b)
{ std::cout<<a+b<<"\n"; }
template <typename F>
class B
{
public:
void fb()(F f1)
{
f1(10.1,10.2);
}
};
int main()
{
B obj(sum_fun); //error
obj.fb(); //error
return 0;
}
There is a misunderstanding of how classes work.
int main()
{
B obj(sum_fun); // calls B constructor with parameter `sum_fun`
obj.fb(); // calls member function B::fb() with no parameters
return 0;
}
Both lines raise an error as
Your class has no constructor which takes a single parameter.
void fb()(F f1) is illegal syntax. To declare a member function, use only one set of parentheses: either void fb() or void fb(F f1). The latter is incorrect in our case, as your member function call obj.fb() passes no parameters.
To fix this, write up a constructor, store the function as a member variable, and use that variable in the function fb().
template <typename F>
class B
{
public:
// constructor, initialises member `m_func` through member initialisation
B(F func) : m_func(func) {}
void fb()
{
m_func(10.1,10.2);
}
private:
F m_func;
};
In C++17, thanks to automatic template deduction, no errors are now emitted. But in lower standards (e.g. C++11), template deduction is lacking and thus, the full templated type needs to be specified when declaring obj.
So in standards below C++17, the main function should be:
int main()
{
// C++11: using a function pointer to denote type
B<double(*)(const double&, const double&)> obj(sum_fun);
// ok in C++17, looks cleaner too
// B obj(sum_fun);
obj.fb();
return 0;
}
Here, double(*)(const double&, const double&) is a function pointer, i.e. a pointer to a function which returns a double and takes two parameters, both of type const double&. Function pointers may be considered as a type, which satisfies the template (template<typename F>).
Just like we do std::vector<int> and std::vector<double>, we can also do std::vector<double(*)(const double&, const double&)> to denote a vector of functions returning double and taking const double& as parameters.
And by the way, sum_fun also raises a warning: nothing is returned even though the return type is double... better specify void as the return type instead.
C++11 Demo
C++17 Demo
Is it possible to pass function as argument directly to B::fb() instead of creating constructor B::B(F) and storing in local variable?
Certainly.
#include <iostream>
void sum_fun(const double& a, const double& b)
{
std::cout << a+b << "\n";
}
template <typename F>
class B
{
public:
void fb(F func)
{
func(10.1,10.2);
}
};
int main()
{
B<void(*)(const double&, const double&)> obj;
obj.fb(sum_fun);
return 0;
}
Note that the member function fb now takes a single parameter func, which we then call. Note also that in C++17, we now can't instantiate the obj with B obj; because this would be ambiguous and the template can't be deduced automatically. Instead, we need to specify the full type B<void(*)(const double&, const double&)>.
However, a recommended alternative over function pointers is to use std::function, which is more versatile and offers a more readable syntax. (std::function Demo)
In C++17 you're allowed to use auto in template paramter list:
template <auto F>
class B
{
public:
void fb()
{
F(10.1,10.2);
}
};
You can then do B<sum_fun>:
int main()
{
B<sum_fun> obj{};
obj.fb();
return 0;
}
For this simplified piece of code I'm getting following error:
error: too few arguments to function
std::cout << f();
int g(int a = 2, int b = 1)
{
return a + b;
}
template<class Func>
void generic(Func f)
{
std::cout << f();
}
int main()
{
generic(g);
}
I cannot clue the reason for why the default parameters of function f are not passing into a function generic. It behaves like f doesn't have any default parameters ...
What's wrong there?
How do I forward default parameters correctly?
g may have default arguments, but the type of &g is still int(*)(int, int), which is not a type that can be called with no arguments. Within generic, we can't differentiate that - we've already lost the context about default arguments.
You can just wrap g in a lambda to preserve the context:
generic([]{ return g(); });
I think the error message to this code quite nicely demonstrates why this isn't possible:
int g(int a=0,int b=0){return 0;}
typedef int (*F1)(int);
int main() {
F1 x = g;
}
error: cannot initialize a variable of type 'F1' (aka 'int (*)(int)') with
an lvalue of type 'int (int, int)': different number of parameters (1 vs 2)
F1 x = g;
^ ~
Even with default parameters, the type of g is still
int (*) (int,int)
and that's what gets deduced when you instantiate the template.
If for some reason you cannot use C++11 or later (i.e. no lambdas, see Barry's answer) and you don't mind a little boilerplate, then you can use a function object:
#include <iostream>
struct g_functor {
int operator()(int a=0,int b=0){ return a;}
};
template <typename T> void foo(T t) { t(); }
int main() { foo(g_functor()); }
Note that you have to create an instance of g_functor to pass it as a parameter.
I'm trying to make an object with a member function that calls another member function like so
foo foo1 = new foo(1, 2);
foo1.print(printj);
I have class:
class foo
{
public:
foo(int x, int y) {i = x; j = y;};
void const print(void const f());
void const printi();
void const printj();
private:
int i;
int j;
}
and my implementation is something like:
void const foo::printi(){
std::cout << i;
}
void const foo::printj(){
std::cout << j;
}
void const foo::print(void const f()){
f();
}
I'm getting an error of
[Error] no matching function for call to 'foo::print()'
Why is that, and how can i fix it?
You need to:
Declare the pointer-to-member function parameter as such:
void const print(void const (foo::*f)());
Pass the member function pointer correctly:
foo1.print(&foo::printj);
Call it with an actual instance (member function call requires an instance):
void const foo::print(void const (foo::*f)()){
(this->*f)();
}
Alternatively you can make the instance an additional parameter or use std::bind or boost::bind to bind them together.
that is not the way how to declare a pointer to a member function you have to declare it this way:
const void (Foo::*ptrFUnc)(void) // or any number of parameters and type
this example shows how:
#include <iostream>
using namespace std;
class Foo
{
public:
void print(const void(Foo::*Bar)()const)const;
const void FooBar()const;
const void Baz ()const;
};
void Foo::print(const void(Foo::*Bar)()const)const
{
(this->*Bar)();
}
const void Foo::FooBar()const
{
cout << "FooBar()" << endl;
}
const void Foo::Baz()const
{
cout << "Baz()" << endl;
}
int main()
{
Foo theFoo;
theFoo.print(theFoo.Baz);
theFoo.print(theFoo.FooBar);
return 0;
}
Note: This answer is aimed at general-case scenarios and future-proofing, and thus examines the possibility of accepting member functions with different numbers of arguments, and of modifying the function in the future. If this isn't an issue, the easiest solution is to manually specify the pointer-to-member-function, as described in the other answers.
A short summary is at the bottom.
There are also two alternatives to declaring the function's type manually, as shown in the other answers, both involving templates:
Declare it manually.
First alternative: Use templates to specialise the pointer-to-member-function, while explicitly specifying the class.
Second alternative: Use templates to deduce the pointer-to-member-function, with no explicit specifications.
In all three cases (manual declaration, and the two alternatives listed here), the usage syntax is identical:
foo1.print(&foo::printj);
As the other answers show, the syntax for declaring it manually is as follows:
// #1: Explicit declaration.
void const foo::print(void const (foo::* f)()) {
(this->*f)();
}
I won't go into much detail on this, as they already cover it. However, this option does have the issue that if you want to accept pointers to member functions which take one or more parameters, you need to manually overload it to accomodate this.
void const foo::print(void const (foo::* f)());
void const foo::print(void const (foo::* f)(int), int);
// And so on...
The first alternative looks a bit complex if you're not used to templates, but is relatively simple to implement.
// 2a: Simplest implementation.
template<typename Return, typename... ArgTypes>
void const foo::print(Return (foo::* f)(ArgTypes...), ArgTypes... args) {
(this->*f)(args...);
}
Or...
// 2b: Works roughly the same way, but gives cleaner, more readable error messages.
template<typename Return, typename... ArgTypes, typename... Args>
void const foo::print(Return (foo::* f)(ArgTypes...), Args... args) {
(this->*f)(args...);
}
This accepts any pointer-to-member-function which points to a member of foo, regardless of return and parameter types. If the function takes parameters, it also accepts a number of parameters equal to that function's.
Note that the primary difference between the two is that if not passed the correct number of parameters for the function, the first will give an error about not being able to deduce ArgTypes... due to mismatched template parameter packs, while the second will give an error about not having the correct number of parameters to call f().
[Mechanically, the difference is that the first uses the same template parameter pack in both the pointer and the parameter list, which requires that it be identical in both places (and thus detects the error as a deduction failure when print() is called), while the second uses a separate template parameter pack for each (and thus detects the error as a parameter count mismatch when the pointed-to function, f, is called).]
The second alternative looks cleaner still, and provides cleaner error messages.
template<typename MemberFunction>
void const foo::print(MemberFunction f){
(this->*f)();
}
This can be easily modified to accept member functions which take parameters, similarly to the first alternative.
// 3: Take pointer-to-member-function and any function parameters as template parameters.
template<typename MemberFunction, typename... Args>
void const foo::print(MemberFunction f, Args... args){
(this->*f)(args...);
}
It will also give the cleanest error message if passed the wrong number of parameters for the function, because the error occurs when calling f instead of at overload resolution or template deduction. This makes it the easiest to troubleshoot, if necessary.
So, this leaves us with three options, one of which can be done either of two ways:
class foo
{
public:
foo(int x, int y) {i = x; j = y; test = 42;};
// -----
// #1.
void const print1(void const (foo::* f)());
// -----
// #2.
template<typename Return, typename... ArgTypes>
void const print2a(Return (foo::* f)(ArgTypes...), ArgTypes... args);
template<typename Return, typename... ArgTypes, typename... Args>
void const print2b(Return (foo::* f)(ArgTypes...), Args... args);
// -----
// #3.
template<typename MemberFunction, typename... Args>
void const print3(MemberFunction f, Args... args);
// -----
void const printi();
void const printj();
// For testing.
void const printParams(int i, bool b, char c, double d);
private:
int i;
int j;
public:
int test;
};
void const foo::print1(void const (foo::* f)()) {
(this->*f)();
}
template<typename Return, typename... ArgTypes>
void const foo::print2a(Return (foo::* f)(ArgTypes...), ArgTypes... args) {
(this->*f)(args...);
}
template<typename Return, typename... ArgTypes, typename... Args>
void const foo::print2b(Return (foo::* f)(ArgTypes...), Args... args) {
(this->*f)(args...);
}
template<typename MemberFunction, typename... Args>
void const foo::print3(MemberFunction f, Args... args) {
(this->*f)(args...);
}
// -----
void const foo::printi(){
std::cout << i;
}
void const foo::printj(){
std::cout << j;
}
void const foo::printParams(int i, bool b, char c, double d) {
std::cout << std::boolalpha;
std::cout << i << ' ' << b << ' ' << c << ' ' << d << '\n';
std::cout << std::noboolalpha;
}
// -----
foo foo1(1, 2);
Now, mechanically, all three options will accept a pointer-to-member-function, and work as intended. There are a few key differences, however:
The first requires the most work to update and maintain (you have to explicitly overload it), but guarantees that print1() will only take pointers-to-member-functions that you specifically allow; if you want it to only take a void const (foo::*)(), it won't take a void const (foo::*)(int) instead. If passed incorrect arguments, its error messages will be the least useful.
The second only takes a pointer-to-member-function for the specified class, but accepts any pointer-to-member-function for that class; this makes it easier to update and maintain. If passed incorrect arguments, its error messages will be somewhat useful, but will usually be about template deduction. Of the two versions, print2b() will give cleaner error messages when passed the wrong number of parameters.
The third takes anything, but gives the cleanest, most useful error messages if used incorrectly. This is because the error is generated when you call f, instead of when you call print3(). This is as easy to update and maintain as the second option, and opens the possibility to perform dispatching based on the type of pointer it's passed.
So, to demonstrate the difference in error messages, let's see what happens if...
[Error messages paraphrased from Clang, GCC, and MSVC.]
[Note that MSVC template parameter lists have trouble with variadic templates, and can't properly output parameter packs. However, the function's name still contains the full template parameter list.]
If passed a pointer-to-member-function with no parameters: All four work properly.
foo1.print1(&foo::printj); // Output: 2
foo1.print2a(&foo::printj); // Output: 2
foo1.print2b(&foo::printj); // Output: 2
foo1.print3(&foo::printj); // Output: 2
If passed a pointer-to-member-function that takes parameters, and its parameters: print1() fails.
foo1.print1(&foo::printParams, 3, true, '&', 8.8); // Error: Too many arguments.
foo1.print2a(&foo::printParams, 3, true, '&', 8.8); // Output: 3 true & 8.8
foo1.print2b(&foo::printParams, 3, true, '&', 8.8); // Output: 3 true & 8.8
foo1.print3(&foo::printParams, 3, true, '&', 8.8); // Output: 3 true & 8.8
If passed a pointer-to-member-function that takes parameters, and the wrong number of parameters: All four fail.
foo1.print1(&foo::printParams, 42); // Error: Too many arguments.
foo1.print2a(&foo::printParams, 42); // Error: Can't deduce template parameters,
// ArgTypes... could be <int, bool, char, double> or <int>.
foo1.print2b(&foo::printParams, 42); // Error: Not enough arguments to call f().
// Note: Clang deduces template parameters as:
// <const void, int, bool, char, double, int>
// Note: GCC deduces template parameters as:
// [with Return = const void; ArgTypes = {int, bool, char, double}; Args = {int}]
// Note: MSVC deduces template parameters as:
// <const void,int,bool,char,double,int>
foo1.print3(&foo::printParams, 42); // Error: Not enough arguments to call f().
// Note: Clang deduces template parameters as:
// <const void (foo::*)(int, bool, char, double), int>
// Note: GCC deduces template parameters as:
// [with MemberFunction = const void (foo::*)(int, bool, char, double); Args = {int}]
// Note: MSVC deduces template parameters as:
// <const void(__thiscall foo::* )(int,bool,char,double),int>
If passed a regular function pointer: All four fail.
void const bar() {}
foo1.print1(&bar); // Error: Can't convert void const (*)() to void const (foo::*)().
foo1.print2a(&bar); // Error: Can't deduce template parameters, mismatched function pointers.
foo1.print2b(&bar); // Error: Can't deduce template parameters, mismatched function pointers.
foo1.print3(&bar); // Error: void const (*)() isn't a pointer-to-member, can't be used with "->*".
If passed a pointer-to-member-function for the wrong class: All four fail.
class oof {
public:
void const printj() {}
};
foo1.print1(&oof::printj); // Error: Can't convert void const (oof::*)() to void const (foo::*)().
foo1.print2a(&oof::printj); // Error: Can't deduce template parameters, mismatched foo* and oof*.
foo1.print2b(&oof::printj); // Error: Can't deduce template parameters, mismatched foo* and oof*.
foo1.print3(&oof::printj); // Error: Can't use a void const (oof::*)() with a foo*.
If passed a pointer-to-member-data: All four fail.
foo1.print1(&foo::test); // Error: Can't convert int foo::* to void const (foo::*)().
foo1.print2a(&foo::test); // Error: Can't deduce template parameters, mismatched
// int foo::* and Return (foo::*)(ArgTypes...).
foo1.print2b(&foo::test); // Error: Can't deduce template parameters, mismatched
// int foo::* and Return (foo::*)(ArgTypes...).
foo1.print3(&foo::test); // Error: int foo::* can't be used as a function.
If passed a regular pointer: All four fail.
foo1.print1(&foo); // Error: Can't convert foo* to void const (foo::*)().
foo1.print2a(&foo); // Error: Can't deduce template parameters, mismatched
// foo* and Return (foo::*)(ArgTypes...).
foo1.print2b(&foo); // Error: Can't deduce template parameters, mismatched
// int foo::* and Return (foo::*)(ArgTypes...).
foo1.print3(&foo); // Error: foo* isn't a pointer-to-member, can't be used with "->*".
If passed an integral value: All four fail.
foo1.print1(3); // Error: Can't convert int to void const (foo::*)().
foo1.print2a(3); // Error: Can't deduce template parameters, mismatched
// int and Return (foo::*)(ArgTypes...).
foo1.print2b(3); // Error: Can't deduce template parameters, mismatched
// int and Return (foo::*)(ArgTypes...).
foo1.print3(3); // Error: int isn't a pointer-to-member, can't be used with "->*".
And so on...
Of these options, print3() consistently gives the cleanest error messages when misused, making it the best option when everything else is equal. print2b() gives cleaner error messages when called with the wrong number of parameters, but otherwise matches print2a().
Summary:
There are three ways to take a pointer-to-member-function, as described above:
Declare it manually, as described in other answers.
void const foo::print(void const (foo::* f)());
Use templates to specialise it, and take any parameters it might need.
template<typename Return, typename... ArgTypes>
void const foo::print(Return (foo::* f)(ArgTypes...), ArgTypes... args);
Or...
template<typename Return, typename... ArgTypes, typename... Args>
void const foo::print(Return (foo::* f)(ArgTypes...), Args... args);
Take the function as a template parameter, and any parameters it may need.
template<typename MemberFunction, typename... Args>
void const foo::print(MemberFunction f, Args... args);
Of these:
The first option gives you the most control over which functions print() is allowed to take, but requires you to explicitly overload it for each type of pointer-to-member-function you want to allow (e.g. void (foo::*)() or int (foo::*)(int, int)); this makes it the least future-proof, because you need to update the function if you add new functions to foo and want it to take them.
The second and third options, conversely, are future-proof, and will take any pointer-to-member-function. However, they don't allow you to restrict what kind of member function you pass, unless you put extra effort into it.
If used incorrectly, the third option will give the cleanest error message, which is useful when troubleshooting. Conversely, the first option will usually emit a conversion error, and the second option will usually emit a "can't deduce template parameters" error. If called with a member function that takes parameters, when not supplied with those parameters, both the third option and the second version of the second option will give the correct error; the third option will emit a cleaner, easier-to-read error, however.
I am trying to build a statically bound delegate class, where the member function is bound at compile time, thereby aiding optimisation.
I have the following code which works exactly how I want it to:
#include <iostream>
namespace thr {
template<typename T, T func>
struct delegate;
template<typename R,
typename C,
typename... A,
R (C::* mem_fun)(A...)>
struct delegate<R(C::*)(A...), mem_fun>
{
delegate(C* obj_)
: _obj(obj_)
{}
R operator()(A... a)
{
return (_obj->*mem_fun)(a...);
}
private:
C* _obj;
};
} // namespace thr
struct foo
{
double bar(int i, int j)
{
return (double)i / (double)j;
}
};
int main()
{
foo f;
typedef thr::delegate<decltype(&foo::bar), &foo::bar> cb;
cb c(&f);
std::cout << c(4, 3);
return 0;
}
However, the usage is not very elegant:
thr::delegate<decltype(&foo::bar), &foo::bar>
I would like to use a function template which deduces the template parameters and returns a delegate instance; something along the lines of (this code does not compile):
template<typename C, typename T, T func>
thr::delegate<T, func> bind(T func, C* obj)
{
return thr::delegate<decltype(func), func>(obj);
}
This would allow for more elegant syntax:
auto cb = bind(&foo::bar, &f);
Is it possible to deduce a non-type parameter in a function template?
Is what I'm trying to achieve even possible?
Would std::function help? http://www2.research.att.com/~bs/C++0xFAQ.html#std-function Your example looks quite close.
I think the compiler supplied STL does pretty horrible things to make it work smoothly. You may want to have a look at as an example before giving up.
Edit: I went out and tried what you try to accomplish. My conclusion is a compile error:
The return type of the bind (delegate) must name the pointer to member because it is your own requirement.
bind should accept the name of the pointer to member to be elegant (i.e. your requirement)
Compiler requires you to not shadow the template parameter with a function parameter or use the name in both parameters and return type.
Therefore one of your requirements must go.
Edit 2: I took the liberty of changing your delegate so bind works as you wish. bind might not be your priority though.
#include <iostream>
namespace thr {
template<typename C,typename R,typename... A>
struct delegate
{
private:
C* _obj;
R(C::*_f)(A...);
public:
delegate(C* obj_,R(C::*f)(A...))
: _obj(obj_),_f(f)
{}
R operator()(A... a)
{
return (_obj->*_f)(a...);
}
};
} // namespace thr
template<class C,typename R,typename... A> thr::delegate<C,R,A...> bind(R(C::*f)(A...),C* obj){
return thr::delegate<C,R,A...>(obj,f);
}
struct foo
{
double bar(int i, int j)
{
return (double)i / (double)j;
}
};
int main()
{
foo f;
auto c = bind(&foo::bar, &f);
std::cout << c(4, 6);
return 0;
}
It is possible to deduce other entities than types in a function signature, but function parameters themselves cannot then be used as template parameters.
Given:
template <size_t I> struct Integral { static size_t const value = I; };
You can have:
template <size_t N>
Integral<N> foo(char const (&)[N]);
But you cannot have:
Integral<N> bar(size_t N);
In the former case, N as the size of the array is part of the type of the argument, in the latter case, N is the argument itself. It can be noticed that in the former case, N appeared in the template parameters list of the type signature.
Therefore, if indeed what you want is possible, the member pointer value would have to appear as part of the template parameter list of the function signature.
There may be a saving grace using constexpr, which can turn a regular value into a constant fit for template parameters:
constexpr size_t fib(size_t N) { return N <= 1 ? 1 : fib(N-1) + fib(N-2); }
Integral<fib(4)> works;
But I am not savvy enough to go down that road...
I do however have a simple question: why do you think this will speed things up ? Compilers are very good at constant propagation and inlining, to the point of being able to inline calls to virtual functions when they can assess the dynamic type of variables at compilation. Are you sure it's worth sweating over this ?
I'm playing around with lambda functions in gcc 4.6.2, and would like to implement a templated "map" function like this:
template<typename A, typename B> std::vector<B> map(const std::vector<A>& orig, const std::function<B(A)> f) {
std::vector<B> rv;
rv.resize(orig.size());
std::transform(begin(orig), end(orig), begin(rv), f);
return rv;
}
This doesn't work, because the test code:
int main(int argc, char **argv) {
std::vector<int> list;
list.push_back(10);
list.push_back(20);
list.push_back(50);
std::vector<int> transformed = map(list, [](int x) -> int { return x + 1; });
std::for_each(begin(transformed), end(transformed), [](int x) { printf("-> %d\n", x); });
return 0;
}
gives this error:
test.cpp:49:80: error: no matching function for call to ‘map(std::vector<int>&, main(int, char**)::<lambda(int)>)’
test.cpp:49:80: note: candidate is:
test.cpp:6:49: note: template<class A, class B> std::vector<B> map(const std::vector<A>&, std::function<B(A)>)
If I remove the templating, and use a vector directly, it compiles fine:
std::vector<int> map(const std::vector<int>& orig, const std::function<int(int)> f) {
std::vector<int> rv;
rv.resize(orig.size());
std::transform(begin(orig), end(orig), begin(rv), f);
return rv;
}
so it must be a problem with the way I'm defining the template.
Has anyone run into this before? I know lambdas are incredibly new.
You don't need to use std::function. Just make the predicate parameter a template value. For example,
template<typename A, typename B> std::vector<B> map(const std::vector<A>& orig, B f) {
std::function<> is more useful as a member value type or for defining non-templated code.
The problem is that the compiler can't figure out what to use for B. In order to determine that type it wants to use the function<> you pass in for f, but you don't pass an std::function<> directly. You pass in something you expect to be used to construct a function<>. And in order to do that implicit construction it needs to know the type of argument. So you've got this circular dependency where the type of argument depends on what you pass in, but what gets passed in depends on the type of argument.
You can break this circular dependency by specifying the template parameters, such as map_<int,int>(list, [](int x) -> char { return x + 1; });
(although I see the functor actually returns a char, not an int, so if the type deduction worked for you here you'd be getting back a vector<char> which cannot be converted to a vector<int> when you assign the result to transformed)
However as has been pointed out, generally templates take functors as just a plain template type:
template<typename A,typename Func>
auto map_(const std::vector<A>& orig, Func f) -> std::vector<decltype(f(A()))> {
std::vector<decltype(f(A()))> rv;
/*...*/
}
(we use the trailing return type because we need to use the expression f in the return type, which isn't available unless the return type comes afterwards.)
This allows the template to deduce the functor type directly and avoids any type conversions and best allows for optimization.
It's also customary to use iterators as arguments on these sorts of functions, in which case your function is just a wrapper around std::transform, so you can just use that directly. I'm not sure there's a whole lot of value in a special version that deals with vectors specifically.
I'm tackling with lambdas too and i noticed that you can declare a function pointer in a function definition's parameter list and when you make a call to that function you can pass a lambda expression as an argument if it matches the function prototype of course.
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
template <typename T,typename C>
struct map {
typedef C (*F)(const T&);
std::vector<C> rv;
map () {}
map (const std::vector<T>& o,F f) {
rv.resize(o.size());
std::transform (o.begin(),o.end(),rv.begin(),f);
}
~map () {}
operator std::vector<C> () const {
return rv;
}
};
int main () {
std::vector<int> asd(5,12);
std::vector<char> transformed=map<int,char>(asd,[](const int& x)->char {return x+1;});
std::copy (transformed.begin(),transformed.end(),std::ostream_iterator<int>(std::cout," "));
}