默认 lambda 作为函数的模板化参数
Default lambda as templated parameter of a function
考虑以下代码
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.
考虑直接重载它:
template <bool b>
void foo(void) {
foo([](){});
}
参见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)
}
默认函数参数不是模板参数推导过程的一部分。引用 [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.
该项目符号和注释表明,由于您没有在对 foo
的调用中为 t
提供参数,因此无法推导出类型 T
。只有在选择调用函数时才会考虑默认的 lambda 参数,而不是之前。
正如所有其他人指出的那样,解决方案是提供一个不带参数的重载,它将使用您想到的默认 lambda 调用模板化的重载。
编译器使用参数 passed 来推断模板类型。如果没有参数,那么编译器如何推断模板类型?
您可以在此处使用 重载 而不是默认参数。
重载的无参数函数可以简单地调用带"default"参数的函数:
template<bool b, typename T> void foo(const T& t) {
// implementation here
}
template<bool b> void foo() {
foo<b>([]() {});
}
你想说一些毫无意义的话。您要求编译器从您的参数中猜测 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
}
另一种(非常有效的)方式 - 默认 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
}
考虑以下代码
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.
考虑直接重载它:
template <bool b>
void foo(void) {
foo([](){});
}
参见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) }
默认函数参数不是模板参数推导过程的一部分。引用 [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.
该项目符号和注释表明,由于您没有在对 foo
的调用中为 t
提供参数,因此无法推导出类型 T
。只有在选择调用函数时才会考虑默认的 lambda 参数,而不是之前。
正如所有其他人指出的那样,解决方案是提供一个不带参数的重载,它将使用您想到的默认 lambda 调用模板化的重载。
编译器使用参数 passed 来推断模板类型。如果没有参数,那么编译器如何推断模板类型?
您可以在此处使用 重载 而不是默认参数。
重载的无参数函数可以简单地调用带"default"参数的函数:
template<bool b, typename T> void foo(const T& t) {
// implementation here
}
template<bool b> void foo() {
foo<b>([]() {});
}
你想说一些毫无意义的话。您要求编译器从您的参数中猜测 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
}
另一种(非常有效的)方式 - 默认 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
}