Default lambda as templated parameter of a function

若如初见. 提交于 2020-08-20 03:09:20

问题


Consider the following code

template<bool b, typename T> void foo(const T& t = []() {}) {
  // implementation here
}

void bar() {
  foo<true>([&](){ /* implementation here */ }); // this compiles
  foo<true>(); // this doesn't compile
}

In the case that doesn't compile I get the following errors:

error C2672: 'foo': no matching overloaded function found
error C2783: 'void foo(const T&)': could not deduce template argument for 'T'

I think it's clear what I want to achieve: let foo be called with and without a client-provided lambda. The compiler is MSVC++2017 version 15.4.4 toolset v141.


回答1:


The compiler uses the arguments passed to deduce the template type. If there's no arguments, then how would the compiler be able to deduce the template type?

You can use overloading instead of default arguments here.

The overloaded non-argument function can simply call the function with the "default" argument:

template<bool b, typename T> void foo(const T& t) {
  // implementation here
}

template<bool b> void foo() {
  foo<b>([]() {});
}



回答2:


Default function arguments are not part of the template argument deduction process. To quote [temp.deduct.partial]/3:

The types used to determine the ordering depend on the context in which the partial ordering is done:

  • In the context of a function call, the types used are those function parameter types for which the function call has arguments. 141

141) Default arguments are not considered to be arguments in this context; they only become arguments after a function has been selected.

That bullet and note indicate that since you didn't provide an argument for t in the call to foo, the type T cannot be deduced. The default lambda argument can only be taken into account if the function is selected to be called, not before.

The solution, as all the others have noted, is to provide an overload without parameters, that will call the templated one with the default lambda you have in mind.




回答3:


Another (very efficient) way - default T to be a null functor.

// no_op is a function object which does nothing, regardless of how many
// arguments you give it. It will be elided completely unless you compile with
// -O0
struct no_op 
{ 
    template<class...Args>
    constexpr void operator()(Args&&...) const {} 
};

// foo defaults to using a default-constructed no_op as its function object
template<bool b, typename T = no_op> void foo(T&& t = T()) 
{    
  // implementation here
    t();
}

void bar() {
  foo<true>([&](){ std::cout << "something\n"; }); // this compiles
  foo<true>(); // this now compiles
}



回答4:


Consider overloading it directly:

template <bool b>
void foo(void) {
  foo([](){});
}

See CppReference:

Non-deduced contexts

4) A template parameter used in the parameter type of a function parameter that has a default argument that is being used in the call for which argument deduction is being done:

Type template parameter cannot be deduced from the type of a function default argument: template void f(T = 5, T = 7);

void g()
{
    f(1);     // OK: calls f<int>(1, 7)
    f();      // error: cannot deduce T
    f<int>(); // OK: calls f<int>(5, 7)
}



回答5:


You are trying to say something that makes no sense. You are asking the compiler to guess T from your arguments, but then you do not provide any argument.

The following code does compile, and does what you want:

template<bool b, typename T> void foo(const T& t) {
  // implementation here
}

template<bool b> void foo() {
  foo<b>([]() {}); // Call actual implementation with empty lambda
}

void bar() {
  foo<true>([&](){ /* implementation here */ }); // this compiles
  foo<true>(); // this now compiles as well
}


来源:https://stackoverflow.com/questions/47495384/default-lambda-as-templated-parameter-of-a-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!