C ++ 11:SFINAE在模板参数中,GCC vs Clang [英] C++11: SFINAE in template parameters, GCC vs Clang

查看:187
本文介绍了C ++ 11:SFINAE在模板参数中,GCC vs Clang的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to implement a little trait-class to determine if a type has overloaded operator() properly, so that I can query a type like so:

FunctorCheck<F, void(int, char)>::value

最初,我有一个想法如何实现这从 Cppcon演讲TMP 之后, a>,我惊讶于这个问题可以更优雅地解决。这是我想出来的,它在Clang 3.5.0上编译和运行:

Originally, I got an idea on how to implement this from this question, but after seeing a Cppcon lecture on TMP, it dawned on me that this problem could be solved much more elegantly. This is what I came up with, and this compiles and runs flawlessly on 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
{};

正如你可能已经注意到的,我使用建议的C ++ 17 void_t 在专门化的模板参数中利用SFINAE。当 FunctorReturn 收到与参数列表不兼容的 Functor 类型时, void_t< FunctorReturn< Functor,Args ...> 将是不成形的,SFINAE将引入并且非专门化版本将被实例化。如果前面的表达式格式良好, std :: is_same 比较返回类型以确定是否有匹配。

As you might have noticed, I'm using the proposed C++17 void_t to exploit SFINAE in the template parameters of the specialization. When FunctorReturn receives a Functor-type that is incompatible with the argument-list, void_t<FunctorReturn<Functor, Args ...>> will be ill-formed, SFINAE will kick in and the non-specialized version will be instantiated. If the former expression is well-formed, std::is_same compares the return-types to determine if we have a match.

在前面提到的讲座中,Walter Brown提到这种技术从Clang的第1天开始工作,并且从第1天开始就没有在GCC上工作,只是因为他们选择了不同的实现标准未能指定。但是,由于这个版本 比我以前更加优雅,有什么我可以做的,使这个编译在GCC(> = 4.9)?

In the lecture mentioned before, Walter Brown mentions that this technique has worked from day 1 on Clang, and has not worked on GCC from day 1, simply because they chose different implementations on something the standard failed to specify. However, given that this version is so much more elegant than what I had before, is there anything I can do to make this compile on GCC (>= 4.9)?

(另外,有没有人知道在最新版本的Visual Studio中的行为?)

(Also, does anyone have any clue as to how this would behave on recent versions of Visual Studio?)

推荐答案

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

This was CWG issue 1558. The unspecified part was treatment of unused arguments in an alias template. In GCC < 5.0 the unused arguments can't result in a substitution failure, hence void_t fails to verify your functor call, and tries to instantiate a class template specialization, which results in a hard error.

GCC(<5.0)是以下实现:

A workaround for GCC (< 5.0) is the following implementation:

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

template <typename... Ts>
using void_t = typename voider<Ts...>::type;

DEMO

这篇关于C ++ 11:SFINAE在模板参数中,GCC vs Clang的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆