C ++ 11:SFINAE在模板参数中,GCC vs Clang [英] C++11: SFINAE in template parameters, 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;
这篇关于C ++ 11:SFINAE在模板参数中,GCC vs Clang的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!