C++ 11:模板参数中的SFINAE,GCC vs Clang

Jor*_*eit 6 gcc templates clang sfinae c++11

我想实现一个小的trait类来确定一个类型是否已operator()正确重载,以便我可以查询类似的类型:

FunctorCheck<F, void(int, char)>::value
Run Code Online (Sandbox Code Playgroud)

最初,我对如何从这个问题实现这个问题有了一个想法,但在看了一篇关于TMPCppcon讲座之后,我突然意识到这个问题可以更优雅地解决.这就是我想出来的,它在Clang 3.5.0上编译并运行完美:

template <typename ...>
using void_t = void;

template <typename Functor, typename ... Args>
using FunctorReturn = decltype(declval<Functor>()(declval<Args>()...));

template <typename Functor, typename Signature, typename = void>
struct FunctorCheck: public std::false_type
{};

template <typename Functor, typename R, typename ... Args>
struct FunctorCheck<Functor, R(Args...), 
    void_t<FunctorReturn<Functor, Args ...>> // SFINAE can kick in here
> : public std::is_same<R, FunctorReturn<Functor, Args ...>>::type
{};
Run Code Online (Sandbox Code Playgroud)

您可能已经注意到,我正在使用建议的C++ 17 void_t在专业化的模板参数中利用SFINAE.当FunctorReturn收到Functor与参数列表不兼容的-type时,void_t<FunctorReturn<Functor, Args ...>>将形成格式,SFINAE将启动并且将实例化非专用版本.如果前一个表达式格式正确,则std::is_same比较返回类型以确定我们是否匹配.

在前面提到的讲座中,Walter Brown提到这种技术从第1天开始就在Clang上工作,并且从第1天开始就没有在GCC上工作,仅仅因为他们在标准未指定的内容上选择了不同的实现.但是,鉴于这个版本比我之前的版本更优雅,我有什么办法可以在GCC(> = 4.9)上进行编译吗?

(另外,有没有人知道在最近的Visual Studio版本中它会如何表现?)

Pio*_*cki 7

这是CWG问题1558.在未指定的部分是一个别名模板处理的未使用的参数.在GCC <5.0中,未使用的参数不会导致替换失败,因此void_t 无法验证您的仿函数调用,并尝试实例化类模板特化,这会导致硬错误.

GCC(<5.0)的解决方法是以下实现:

template <typename...>
struct voider
{
    using type = void;
};

template <typename... Ts>
using void_t = typename voider<Ts...>::type;
Run Code Online (Sandbox Code Playgroud)

DEMO


归档时间:

查看次数:

802 次

最近记录:

10 年,5 月 前