我尽可能地简化了问题,所以这里是有问题的函数:
class Test
{
public:
template<class T>
void ExecuteFunction(std::function<void(T)> f)
{
}
};
如果我使用int-typing调用该函数,则一切正常,但是,如果我使用空类型的lambda调用它,它将不再编译。
Test test;
test.ExecuteFunction<void>( // doesn't compile
[](void)->void
{
int i = 5;
});
test.ExecuteFunction<int>( // this compiles
[](int)->void
{
int i = 5;
});
编译器错误:
Error C2672 'Test::ExecuteFunction': no matching overloaded function found
Error C2770 invalid explicit template argument(s) for 'void Test::ExecuteFunction(std::function<void(P)>)'
Error (active) no instance of function template "Test::ExecuteFunction" matches the argument list
有没有解决的办法?有人将如何指定模板,以便两个调用都能正常工作?
答案 0 :(得分:4)
当然,括号内的void
只是老式的C型糖。您必须专门设计模板:
template<> void Test::ExecuteFunction<void>(std::function<void()> f) {}
如果无法编译,可以使用帮助程序模板封装类型选择:
#include <iostream>
#include <functional>
template<class T> struct callable {
using type = std::function<void(T)>;
};
template<class T> using callable_t =
typename callable<T>::type;
template<> struct callable<void> {
using type = std::function<void()>;
};
class Test
{
public:
template<class T>
void ExecuteFunction(callable_t<T> f) {}
};
int main() {
Test test;
test.ExecuteFunction<void>( // does compile
[](void)->void {});
test.ExecuteFunction<int>( // this compiles
[](int)->void {});
}
但是请注意,这种方式还必须对传递的参数做一些处理(在您的示例中,通用案例的参数是一元的,但是void
的特殊化要求使用空函数对象)。
答案 1 :(得分:3)
您可以像这样向类添加重载:
// as before:
template<class T>
void ExecuteFunction(std::function<void(T)> f) {}
// new overload (not a template):
void ExecuteFunction(std::function<void()> f) {}
由于您无论如何都不能使用类型推导,因此现在可以通过不指定任何模板参数来显式调用此函数。
Test test;
test.ExecuteFunction(
[](void)->void
{
int i = 5;
});
答案 2 :(得分:2)
Is too late to play?
I propose another solution based on a custom type trait (with a specialization for void
) that, given a T
type, define the correct std::function
type
; i mean
template <typename T>
struct getFuncType
{ using type = std::function<void(T)>; };
template <>
struct getFuncType<void>
{ using type = std::function<void()>; };
This way your ExecuteFunction()
simply become
template <typename T>
void ExecuteFunction (typename getFuncType<T>::type f)
{
}
If you want simplify a little the use of getFuncType
, you can add a using
helper to extract the type
template <typename T>
using getFuncType_t = typename getFuncType<T>::type;
so the ExecuteFunction()
can be simplified as follows
template <typename T>
void ExecuteFunction (getFuncType_t<T> f)
{
}