我的模板fu相当弱.我有这个代码:
template<typename T>
void Foo(void(*func)(T*)) { }
void Callback(int* data) { }
int Test()
{
Foo(Callback);
}
Run Code Online (Sandbox Code Playgroud)
...但我想要比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
}
Run Code Online (Sandbox Code Playgroud)
(我仍然在争论这是否实际上更具可读性,但这是一个单独的问题.)
我怎样才能帮助编译器找出T是什么而不需要在调用者中明确指定它?
您可以T使用traits类从函数类型中提取.
template<class F>
struct CallbackTraits;
template<class T>
struct CallbackTraits<void(*)(T)>
{
typedef T ArgumentType;
};
Run Code Online (Sandbox Code Playgroud)
您的示例可以像这样修改:
template<typename F>
void Foo(F func)
{
typedef typename CallbackTraits<F>::ArgumentType T;
}
void Callback(int* data) { }
int Test()
{
Foo(Callback);
}
Run Code Online (Sandbox Code Playgroud)
此类技术用于boost类型特征库: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*)) { }
Run Code Online (Sandbox Code Playgroud)
可以使用c ++ 11的别名模板实现另一种可读性更高的替代语法,如下所示:
template<typename T>
using Identity = T;
template<typename T>
void Foo(Identity<void(T*)> func) { }
Run Code Online (Sandbox Code Playgroud)
不幸的是,最新的MSVC无法编译,报告内部编译器错误.