如何强制编译器识别模板函数中的 lambda 类型?
How do I force the compiler to recognize lambda type in templated function?
这是一个完整的小程序。对 test1()
和 test2()
的前三个调用编译正确,对 运行 的最后一个调用 test2()
不编译。如何让编译器在不指定调用类型的情况下识别对 test2() 的调用?
#include <functional>
#include <iostream>
// using function pointer
template <typename T>
T test1(T arg, T (*fnptr)(T)) {
return fnptr(arg);
}
// using a lambda
template <typename T>
T test2(T arg, std::function<T (T)> mapfn) {
return mapfn(arg);
}
int dbl(int v) {
return 2 * v;
}
int main() {
// v1a: compiles, runs without error
int v1a = test1<int>(11, dbl);
std::cout << v1a << std::endl;
// v2a: compiles, runs without error
int v2a = test2<int>(11, [=](int arg) { return 2 * arg; });
std::cout << v2a << std::endl;
// v1b (without template type): compiles, runs without error
int v1b = test1(11, dbl);
std::cout << v1b << std::endl;
// v2a (without template type): doesn't compile: no matching fn
int v2b = test2(11, [=](int arg)->int { return 2 * arg; });
std::cout << v2b << std::endl;
return 0;
}
编译器生成以下消息:
$ g++ -O3 -Wall -std=c++11 -o sketch_tiny sketch_tiny.cpp
sketch_tiny.cpp:34:13: error: no matching function for call to 'test2'
int v2b = test2(11, [=](int arg)->int { return 2 * arg; });
^~~~~
sketch_tiny.cpp:12:3: note: candidate template ignored: could not match
'function<type-parameter-0-0 (type-parameter-0-0)>' against '<lambda at
sketch_tiny.cpp:34:23>'
T test2(T arg, std::function<T (T)> mapfn) {
^
1 error generated.
有没有办法让编译器在不使用 test2<int>(...)
类型说明符的情况下识别对 test2(...)
的调用?
为了它的价值,这里是编译环境:
$ g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.1.0
Thread model: posix
模板参数推导仅查看一组非常有限的隐式转换。 lambda 不是 std::function
,因此模板参数推导失败。
通常有两种方法可以解决:
将lambda的类型作为单独的模板参数:
template <typename T, typename F>
T test2(T arg, F mapfn) {
return mapfn(arg);
}
这是最有效的方法。
如果出于某种原因你真的想使用 std::function
并支付关联类型擦除成本,你可以将 std::function<T(T)>
放入非推导上下文中。
template <typename T> struct identity { using type = T; };
template <typename T> using non_deduced = typename identity<T>::type;
template <typename T>
T test2(T arg, non_deduced<std::function<T (T)>> mapfn) {
return mapfn(arg);
}
这是一个完整的小程序。对 test1()
和 test2()
的前三个调用编译正确,对 运行 的最后一个调用 test2()
不编译。如何让编译器在不指定调用类型的情况下识别对 test2() 的调用?
#include <functional>
#include <iostream>
// using function pointer
template <typename T>
T test1(T arg, T (*fnptr)(T)) {
return fnptr(arg);
}
// using a lambda
template <typename T>
T test2(T arg, std::function<T (T)> mapfn) {
return mapfn(arg);
}
int dbl(int v) {
return 2 * v;
}
int main() {
// v1a: compiles, runs without error
int v1a = test1<int>(11, dbl);
std::cout << v1a << std::endl;
// v2a: compiles, runs without error
int v2a = test2<int>(11, [=](int arg) { return 2 * arg; });
std::cout << v2a << std::endl;
// v1b (without template type): compiles, runs without error
int v1b = test1(11, dbl);
std::cout << v1b << std::endl;
// v2a (without template type): doesn't compile: no matching fn
int v2b = test2(11, [=](int arg)->int { return 2 * arg; });
std::cout << v2b << std::endl;
return 0;
}
编译器生成以下消息:
$ g++ -O3 -Wall -std=c++11 -o sketch_tiny sketch_tiny.cpp
sketch_tiny.cpp:34:13: error: no matching function for call to 'test2'
int v2b = test2(11, [=](int arg)->int { return 2 * arg; });
^~~~~
sketch_tiny.cpp:12:3: note: candidate template ignored: could not match
'function<type-parameter-0-0 (type-parameter-0-0)>' against '<lambda at
sketch_tiny.cpp:34:23>'
T test2(T arg, std::function<T (T)> mapfn) {
^
1 error generated.
有没有办法让编译器在不使用 test2<int>(...)
类型说明符的情况下识别对 test2(...)
的调用?
为了它的价值,这里是编译环境:
$ g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.1.0
Thread model: posix
模板参数推导仅查看一组非常有限的隐式转换。 lambda 不是 std::function
,因此模板参数推导失败。
通常有两种方法可以解决:
将lambda的类型作为单独的模板参数:
template <typename T, typename F> T test2(T arg, F mapfn) { return mapfn(arg); }
这是最有效的方法。
如果出于某种原因你真的想使用
std::function
并支付关联类型擦除成本,你可以将std::function<T(T)>
放入非推导上下文中。template <typename T> struct identity { using type = T; }; template <typename T> using non_deduced = typename identity<T>::type; template <typename T> T test2(T arg, non_deduced<std::function<T (T)>> mapfn) { return mapfn(arg); }