C++11:模板参数中的 SFINAE,GCC vs Clang
C++11: SFINAE in template parameters, GCC vs Clang
我想实现一个小特征-class 来确定一个类型是否已正确重载 operator()
,这样我就可以像这样查询一个类型:
FunctorCheck<F, void(int, char)>::value
最初,我从 this question, but after seeing a Cppcon lecture on 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++17 void_t
在专业化的模板参数中利用 SFINAE。当 FunctorReturn
接收到与参数列表不兼容的 Functor
类型时,void_t<FunctorReturn<Functor, Args ...>>
将格式错误,SFINAE 将启动并且将实例化非专用版本。如果前一个表达式格式正确,std::is_same
比较 return 类型以确定我们是否匹配。
在前面提到的讲座中,Walter Brown 提到这项技术从第一天开始就在 Clang 上发挥作用,并且 从第一天起就没有在 GCC 上发挥作用,仅仅是因为他们选择了不同的标准未能指定的东西的实现。但是,考虑到这个版本 比我以前的版本 优雅得多,我能做些什么来在 GCC 上进行编译( >= 4.9)?
(另外,有没有人知道这在 Visual Studio 的最新版本上会如何表现?)
这是 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,并尝试实例化 class 模板特化,这会导致硬错误。
GCC (< 5.0) 的解决方法是以下实现:
template <typename...>
struct voider
{
using type = void;
};
template <typename... Ts>
using void_t = typename voider<Ts...>::type;
我想实现一个小特征-class 来确定一个类型是否已正确重载 operator()
,这样我就可以像这样查询一个类型:
FunctorCheck<F, void(int, char)>::value
最初,我从 this question, but after seeing a Cppcon lecture on 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++17 void_t
在专业化的模板参数中利用 SFINAE。当 FunctorReturn
接收到与参数列表不兼容的 Functor
类型时,void_t<FunctorReturn<Functor, Args ...>>
将格式错误,SFINAE 将启动并且将实例化非专用版本。如果前一个表达式格式正确,std::is_same
比较 return 类型以确定我们是否匹配。
在前面提到的讲座中,Walter Brown 提到这项技术从第一天开始就在 Clang 上发挥作用,并且 从第一天起就没有在 GCC 上发挥作用,仅仅是因为他们选择了不同的标准未能指定的东西的实现。但是,考虑到这个版本 比我以前的版本 优雅得多,我能做些什么来在 GCC 上进行编译( >= 4.9)?
(另外,有没有人知道这在 Visual Studio 的最新版本上会如何表现?)
这是 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,并尝试实例化 class 模板特化,这会导致硬错误。
GCC (< 5.0) 的解决方法是以下实现:
template <typename...>
struct voider
{
using type = void;
};
template <typename... Ts>
using void_t = typename voider<Ts...>::type;