我的模板符比较弱。我有这段代码:
template<typename T>
void Foo(void(*func)(T*)) { }
void Callback(int* data) { }
int Test()
{
Foo(Callback);
}
...但我想要比 C 的 void(*func)(T*)
讨厌的函数指针语法更具可读性的东西。
我团队中有人建议这样做:
template<typename T>
struct Types
{
typedef void Func(T*);
};
template<typename T>
void Foo2(typename Types<T>::Func* func) {}
void Test2()
{
Foo2(Callback); // could not deduce template argument for 'T'
Foo2<int>(Callback); // ok
}
(我仍在争论这是否实际上更具可读性,但这是一个单独的问题。)
我怎样才能帮助编译器找出 T 是什么而不需要在调用者中明确指定它?
最佳答案
您可以使用特征类从函数类型中提取 T
。
template<class F>
struct CallbackTraits;
template<class T>
struct CallbackTraits<void(*)(T)>
{
typedef T ArgumentType;
};
你的例子可以这样修改:
template<typename F>
void Foo(F func)
{
typedef typename CallbackTraits<F>::ArgumentType T;
}
void Callback(int* data) { }
int Test()
{
Foo(Callback);
}
boost type-traits 库中使用了此技术: http://www.boost.org/doc/libs/1_57_0/libs/type_traits/doc/html/boost_typetraits/reference/function_traits.html
这篇博文更详细地介绍了该技术的实现: https://functionalcpp.wordpress.com/2013/08/05/function-traits/
不幸的是,这种方法在 Foo
的签名中隐藏了关于传入参数的约束的信息。在上面的示例中,参数必须是 void(T*) 类型的函数
。
此替代语法与原始示例的作用相同,但可读性稍强:
template<typename T>
void Foo(void func(T*)) { }
另一种可能更具可读性的替代语法可以使用 c++11 的别名模板实现,如下所示:
template<typename T>
using Identity = T;
template<typename T>
void Foo(Identity<void(T*)> func) { }
不幸的是,最新的 MSVC 无法编译它,报告内部编译器错误。
关于c++ - 如何让 C++ 编译器间接推导 T?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27566409/