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.
Related
What is the correct way to accept a parameter pack for perfect-forwarding, such that it will take any type and simply forward them? The following code works on regular types but fails on pointer types:
template<typename ...A>
void b(A &&... args)
{}
template<typename ...A>
void a(A &&... args)
{
b(std::forward<A>(args)...);
}
int main() {
// ok
a<int>(5);
// error: cannot bind rvalue reference of type ‘int*&&’ to lvalue of type ‘int*’
int *foo = nullptr;
a<int*>(foo);
return 0;
}
[edit] Thanks for the quick and great replies! I oversimplified - this is a closer example of the problem I am trying to solve:
#include <iostream>
using namespace std;
template<typename F>
struct fun;
template<typename F, typename ...A>
struct fun<F(A...)>
{
void b(A &&... args)
{}
void a(A &&... args)
{
b(std::forward<A>(args)...);
}
};
int main() {
// ok
fun<void(int)> f1;
f1.a(5);
// error: cannot bind 'int' lvalue to 'int&&'
fun<void(int)> f2;
int x = 5;
f2.a(x);
return 0;
}
In this case, I don't have the luxury to let the template adjust automatically... Any idea how this can be achieved?
[edit 2] as pointed out in the comments, this has nothing to do with pointers, I updated my sample to simply use an lvalue
You should not specify template arguments explicitly; which just prevents template argument deduction from working with forwarding reference, and yields unexpected result.
a<int>(5); // A is specified as int then function parameter's type is int&&.
// 5 is an rvalue and could be bound to int&&
a<int*>(foo); // A is specified as int* then function parameter's type is int* &&.
// foo is an lvalue and couldn't be bound to int* &&
Just
a(5); // 5 is rvalue, then A is deduced as int and function parameter's type collapses to int&&
int *foo = nullptr;
a(foo); // foo is lvalue, then A is deduced as int* & and function parameter's type collapses to int* &
EDIT
Firstly both the member functions b and a are not template, and their parameters are not declared as forwarding reference at all.
The code doesn't work because
fun<void(int)> f2;
int x = 5;
f2.a(x); // A is specified as int then function parameter's type is int &&.
// x is an lvalue and couldn't be bound to int &&
I'm not sure about your intent, you can change it to
fun<void(int&)> f2;
// ^
int x = 5;
f2.a(x); // A is specified as int& then function parameter's type collapses to int&.
// x is an lvalue and could be bound to int&
Or make them function templates and still apply forwarding reference.
template <typename... T>
void b(T &&... args)
{}
template <typename... T>
void a(T &&... args)
{
b(std::forward<T>(args)...);
}
This question already has answers here:
C++11 does not deduce type when std::function or lambda functions are involved
(3 answers)
Closed 2 years ago.
#include <functional>
template <typename M>
M g(std::function<M(int)> f) {
return f(0);
}
int main() {
g([](int x){return x + 1;});
return 0;
}
I want to express something like "the (only) argument passed to function g should be a callable object that has int as type of the parameter".
G++ 9.3.0 says
prog.cc: In function 'int main()':
prog.cc:8:31: error: no matching function for call to 'g(main()::<lambda(int)>)'
8 | g([](int x){return x + 1;});
| ^
prog.cc:3:3: note: candidate: 'template<class M> M g(std::function<M(int)>)'
3 | M g(std::function<M(int)> f) {
| ^
prog.cc:3:3: note: template argument deduction/substitution failed:
prog.cc:8:31: note: 'main()::<lambda(int)>' is not derived from 'std::function<M(int)>'
8 | g([](int x){return x + 1;});
| ^
What is wrong with the above attempt? And how should I achieve that intention?
You may want to see the code snippet on Wandbox here.
First, write a simple meta-function that gives the type of the argument of a unary function pointer:
template<class Ret, class Arg>
auto arg(Ret(*)(Arg)) -> Arg;
Then, in the body of g, you can static_assert that the passed in callable (when decayed to a function pointer), has a single parameter of type int:
template <typename Function>
auto g(Function f) {
static_assert(std::is_same_v<decltype(arg(+f)), int>);
return f(0);
}
Now calls to g will only compile if this constraint is satisfied:
int a(int x) { return x + 1; }
int b(double x) { return x + 1; }
int main() {
g([](int x){return x + 1;}); // ok
g([](char x){return x + 1;}); // error
g([](int x, int){return x + 1;}); // error
g(a); // ok
g(b); // error
}
Here's a demo.
Counterintuitively, you're not actually supposed to use std::function to take a function parameter. Instead, you just need a plain template parameter.
Using a plain template parameter works with std::function. But it also works with function pointers, and will let the function use a lambda (or any other class with an
operator()) directly, without the performance hit of std::function.
template <typename F>
auto g(F f) -> decltype(f(std::declval<int>())) { //alternatively, `decltype(f(0))`
return f(0);
}
If f does not have a member function which can take the expression 0 as input, then compilation will fail, so the constraint is enforced. This is actually the case regardless of whether you include the -> decltype part.
Actually answering the question in the title is a bit trickier. There are two things at play:
The first is that a lambda expression is not a std::function instantiation, even if it can be wrapped inside of one. A given concrete std::function instantiation, such as std::function<int(int)>, has a constructor which will convert from a lambda, and that's how we typically use std::function.
However, implicit conversions do not play well with templates. Either a function argument is used to deduce template parameters, in which case that function argument must match, or the function argument is totally concrete, in which case implicit conversions can be performed. But not both, which is what you had tried to do.
The below code worked for me
#include <iostream>
#include <functional>
template <typename M>
M g(std::function<M (int)> f) {
return f(0);
}
int main() {
std::cout << g<int>([](int x){return x + 1; });
return 0;
}
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;
}
I was experimenting with templates and forwarding. Wrote some simple experimental code which surprised me. I would like to better understand this mechanism, probably I lack some knowledge here and therefore I ask for help. Could you please explain why the two of my calls in the code below don't compile (PLACE 2 and 3)?
#include <iostream>
#include <memory>
#include <utility>
using namespace std;
void h2rvalref(int&& i) { cout << "h2rvalref" << endl; }
void h2ref(int& i) { cout << "h2ref" << endl; }
void h2val(int i) { cout << "h2val" << endl; }
template <class T, class X>
void h1(T&& t, X x) { x(forward<T>(t)); }
int main()
{
// PLACE (1)
h1<int, decltype(h2rvalref)>(1, h2rvalref);
auto b = 1;
// PLACE (2)
// h1<int, decltype(h2ref)>(b, h2ref); // --> ERROR - no matching function..., cannot convert 'b' (type 'int') to type 'int&&'
// PLACE (3)
// h1<int, decltype(h2val)>(b, h2val); // --> ERROR - no matching function..., cannot convert 'b' (type 'int') to type 'int&&'
}
I don't understand why the error says something about converting int to int&& when I have value b of type int.
The problem is that you are providing explicit template arguments to the function. Forwarding arguments does not work when you explicitly provide the template arguments for the type you want to forward (unless you really know what you are doing).
template <class T, class X>
void h1(T&& t, X x) { x(forward<T>(t)); }
When you write h1<int, decltype(h2ref)>, you get a function like this:
void h1(int&& t, decltype(h2ref) x) { x(forward<int>(t)); }
int&& is a different type from int and cannot be bound to an lvalue of type int such as the b that you pass in; it can only be bound to rvalues of type int
If you leave off the template arguments, it just works:
h1(b, h2ref);
This will instantiate a function that looks like this:
void h1(int& t, // int& && collapses to just int&
decltype(h2ref) x) {
x(forward<int&>(t));
}
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. :)