简体   繁体   中英

Why can't my C++ compiler deduce template argument for boost function?

I define a method like so:

template <class ArgT>
void foo(ArgT arg, ::boost::function< void(ArgT) > func)
{
    func(arg);
}

and use it like this --for instance--:

foo(2, [](int i) -> void { cout << i << endl; });

Why can't the compiler deduce the type since it's definitely an int ?

I get 'void foo(ArgT,boost::function<void(ArgT)>)': could not deduce template argument for 'boost::function<void(ArgT)>' from 'anonymous-namespace'::<lambda0>' .

While C++ lambdas are strictly monomorphic, they are merely shorthand for function objects (aka functors), and in general functors can be polymorphic; ie, their call operators can be overloaded or templated. As a result, functors (and, consequently, lambdas) are never implicitly convertible to templated std::function<> (or boost::function<> ) instances because functors' operator() argument types are not automatically inferable.

To phrase it slightly differently, the natural type of your lambda expression is a functor with a parameterless constructor and an operator() with the signature void operator ()(int) const . However obvious this fact may be to you and I, it's not automatically inferrable that ArgT should resolve to int because lambdas are functors and functors' operator() s are possible to overload and template.

TL;DR: What you want isn't possible.

You want a conversion from the lambda function to boost::function<void(ArgT)> where ArgT is to be deduced. As a general rule, you cannot have type deduction and conversion in the same argument of a function: no conversions take place when deducing a template parameter .

The reasoning behind this is as follows. There are three types involved here: (1) the template parameter, (2) the function parameter type, (3) the passed object type. Two of the types (1 and 2) can be deduced from one another, but both are unknown. If the compiler can assume 2 and 3 are the same type, the problem is solved, but if all the compiler knows is that 3 can be converted to 2 there could be any number of possible solutions, and the compiler is not expected to solve the problem. In practice we know that in this particular case there is only one possible solution, but the standard does not make a distinction between cases.

The rule above applies in all deducible contexts, even if the template parameter can be deduced from another function parameter . The solution here is make the relevant function parameter a non-deducible context , ie a context in which the compiler will never attempt to deduce the template parameter from the function parameter. This can be done as follows:

template <class T> struct identity { typename T type; };

template <class ArgT>
void foo(ArgT arg, typename identity<::boost::function<void(ArgT)>>::type func)
{
  func(arg);
} 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM