SFINAE:检测成员变量的存在不适用于g ++

And*_*dre 5 c++ g++ sfinae

我正在尝试结合此答案中用于检测类是否具有成员变量的方法,x并根据此答案选择不同的实现enable_if

基本上,我想编写一个trait类,给定一个type T,它可以访问成员(T::x如果存在),否则提供一个默认值。

以下代码无法在g ++上编译:(Compiler Explorer

#include <iostream>
#include <type_traits>

// classes with / without x member
struct WithX { static constexpr int x = 42; };
struct WithoutX {};

// trait to detect x
template <typename T, typename = void>
struct HasX : std::false_type { };

template <typename T>
struct HasX <T, decltype((void) T::x)> : std::true_type { };

// trait to provide default for x
template <typename T>
struct FooTraits
{
    template <bool enable = HasX<T>::value>
    static constexpr std::enable_if_t< enable, size_t> x() { return T::x; }
    template <bool enable = HasX<T>::value>
    static constexpr std::enable_if_t<!enable, size_t> x() { return 1; }

};


int main() {
    std::cout << HasX<WithX>::value << std::endl;
    // Uncomment the following line to make this compile with g++
    //std::cout << HasX<WithoutX>::value << std::endl;
    std::cout << FooTraits<WithoutX>::x() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

g ++给出了错误消息

error: 'x' is not a member of 'WithoutX'
  struct HasX <T, decltype((void) T::x)> : std::true_type { };
Run Code Online (Sandbox Code Playgroud)

首先应该检测x成员是否是成员。但是,奇怪的是,如果我取消注释它HasX<WithoutX>::value自己实例化的倒数第二行,则g ++编译时不会出错(Compiler Explorer)。

clang和msvc都可以在Compiler Explorer上编译而没有问题。

怎么了

Jar*_*d42 1

事实上,切换评论:

//std::cout << HasX<WithoutX>::value << std::endl;
Run Code Online (Sandbox Code Playgroud)

确实是 gcc bug 的好兆头。

看来 gcc 对您的表单有问题:

template <typename T>
struct HasX <T, decltype((void) T::x)> : std::true_type {};
Run Code Online (Sandbox Code Playgroud)

更典型的方法是使用std::void_t

template <typename T>
struct HasX <T, std::void_t<decltype(T::x)>> : std::true_type {};
Run Code Online (Sandbox Code Playgroud)

这确实解决了Demo 的问题。