如何让C++编译器间接推断出T?

sco*_*obi 8 c++ templates

我的模板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是什么而不需要在调用者中明确指定它?

wil*_*llj 9

您可以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无法编译,报告内部编译器错误.