将 lambda 传递给 void 指定模板失败
passing lambda to void specified template fails
我尽可能地简化了问题,所以这里是有问题的函数:
class Test
{
public:
template<class T>
void ExecuteFunction(std::function<void(T)> f)
{
}
};
如果我用 int 类型调用函数,一切正常,但是,如果我用 void 类型的 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
有办法解决这个问题吗?某人将如何指定模板以便两个调用都能正常工作?
当然,括号中的 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
的特化需要一个空函数对象)。
您可以像这样向 class 添加重载:
// 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;
});
来不及玩了?
我提出了另一种基于自定义类型特征(具有 void
的特化)的解决方案,给定 T
类型,定义正确的 std::function
type
;我是说
template <typename T>
struct getFuncType
{ using type = std::function<void(T)>; };
template <>
struct getFuncType<void>
{ using type = std::function<void()>; };
这样你的ExecuteFunction()
就变成了
template <typename T>
void ExecuteFunction (typename getFuncType<T>::type f)
{
}
如果你想稍微简化 getFuncType
的使用,你可以添加一个 using
助手来提取 type
template <typename T>
using getFuncType_t = typename getFuncType<T>::type;
所以ExecuteFunction()
可以简化如下
template <typename T>
void ExecuteFunction (getFuncType_t<T> f)
{
}
我尽可能地简化了问题,所以这里是有问题的函数:
class Test
{
public:
template<class T>
void ExecuteFunction(std::function<void(T)> f)
{
}
};
如果我用 int 类型调用函数,一切正常,但是,如果我用 void 类型的 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
有办法解决这个问题吗?某人将如何指定模板以便两个调用都能正常工作?
当然,括号中的 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
的特化需要一个空函数对象)。
您可以像这样向 class 添加重载:
// 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;
});
来不及玩了?
我提出了另一种基于自定义类型特征(具有 void
的特化)的解决方案,给定 T
类型,定义正确的 std::function
type
;我是说
template <typename T>
struct getFuncType
{ using type = std::function<void(T)>; };
template <>
struct getFuncType<void>
{ using type = std::function<void()>; };
这样你的ExecuteFunction()
就变成了
template <typename T>
void ExecuteFunction (typename getFuncType<T>::type f)
{
}
如果你想稍微简化 getFuncType
的使用,你可以添加一个 using
助手来提取 type
template <typename T>
using getFuncType_t = typename getFuncType<T>::type;
所以ExecuteFunction()
可以简化如下
template <typename T>
void ExecuteFunction (getFuncType_t<T> f)
{
}