默认lambda作为函数

时间:2017-11-26 11:02:51

标签: c++ templates lambda c++17 default-parameters

考虑以下代码

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
}

如果没有编译,我会收到以下错误:

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

我认为我想要实现的目标很简单:让foo使用和不使用客户端提供的lambda来调用。编译器是MSVC ++ 2017版本15.4.4工具集v141。

5 个答案:

答案 0 :(得分:8)

默认函数参数不是模板参数推导过程的一部分。引用[temp.deduct.partial]/3

  

用于确定排序的类型取决于上下文   部分排序完成:

     
      
  • 在函数调用的上下文中,使用的类型是函数调用具有参数的函数参数类型。    141
  •   
     

<子>   141)默认参数在此不被视为参数   上下文;它们只在函数出现后才成为参数   选择。   

该子弹和注释表明,由于您未在t的调用中为foo提供参数,因此无法推断出类型T。如果选择调用该函数,则不能考虑默认的lambda参数,而不是之前。

正如所有其他人所指出的那样,解决方案是提供一个没有参数的重载,它将使用你想到的默认lambda调用模板化的。

答案 1 :(得分:2)

编译器使用参数传递来推断模板类型。如果没有参数,那么编译器如何能够推导出模板类型?

您可以在此处使用重载而不是默认参数。

重载的非参数函数可以简单地使用&#34;默认&#34;来调用函数。参数:

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

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

答案 2 :(得分:1)

考虑直接重载:

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

请参阅CppReference

  

非推断的上下文

     

4)在函数参数的参数类型中使用的模板参数,该参数具有在正在进行参数推断的调用中使用的默认参数:

  

无法从函数默认参数的类型推导出类型模板参数:   模板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)
}

答案 3 :(得分:1)

另一种(非常有效的)方式 - 默认T为空仿函数。

// 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 :(得分:0)

你试图说一些毫无意义的话。您要求编译器从您的参数中猜测T,但是您不提供任何参数。

以下代码可以编译,并执行您想要的操作:

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
}
相关问题