我想实现一个小小的trait-class来确定类型是否operator()
正确地重载,以便可以查询如下类型:
FunctorCheck<F, void(int, char)>::value
最初,我对这个问题有一个解决方案,但是看了Cppcon关于TMP的演讲后,我突然意识到可以更优雅地解决这个问题。这是我想出的,它可以在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 ++ 17void_t
在专业化模板参数中利用SFINAE。当FunctorReturn
接收到Functor
与参数列表不兼容的-type时,其void_t<FunctorReturn<Functor, Args ...>>
格式将不正确,SFINAE将加入,非专业版本将被实例化。如果前一个表达式格式正确,则std::is_same
比较返回类型以确定我们是否有匹配项。
在前面提到的演讲中,Walter Brown提到该技术从Clang的第一天起就起作用了,而从第一天起就没有在GCC上起作用,这仅仅是因为他们在标准未指定的内容上选择了不同的实现。但是,鉴于此版本比我以前拥有的版本更加优雅,我是否可以做些什么才能在GCC(> = 4.9)上进行编译?
(此外,是否有人对最新版本的Visual Studio的行为有任何线索?)
这是CWG问题1558。在未指定的部分是一个别名模板处理的未使用的参数。在GCC <5.0中,未使用的参数不会导致替换失败,因此void_t
无法验证您的functor调用,并尝试实例化类模板的特殊化,从而导致硬错误。
GCC(<5.0)的一种解决方法是以下实现:
template <typename...>
struct voider
{
using type = void;
};
template <typename... Ts>
using void_t = typename voider<Ts...>::type;
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句