c++ - 如何检测类中是否确实存在特定的成员变量?

标签 c++ templates variables member

我故意使用与 this question 完全相同的标题因为我觉得被接受的答案并不能解决我遇到的问题。

我正在寻找一种方法来检测某个类是否有某个成员变量。值得注意的是,我正在寻找一个变量,而不是成员函数或其他任何东西。

这是我链接的问题中提供的示例:

template<typename T> struct HasX { 
    struct Fallback { int x; }; // introduce member name "x"
    struct Derived : T, Fallback { };

    template<typename C, C> struct ChT; 

    template<typename C> static char (&f(ChT<int Fallback::*, &C::x>*))[1]; 
    template<typename C> static char (&f(...))[2]; 

    static bool const value = sizeof(f<Derived>(0)) == 2;
}; 

struct A { int x; };
struct B { int X; };

int main() { 
    std::cout << HasX<A>::value << std::endl; // 1
    std::cout << HasX<B>::value << std::endl; // 0
}

但是如果我们这样做,我们将得到完全相同的输出

template<typename T> struct HasX { 
    struct Fallback { int x; }; // introduce member name "x"
    struct Derived : T, Fallback { };

    template<typename C, C> struct ChT; 

    template<typename C> static char (&f(ChT<int Fallback::*, &C::x>*))[1]; 
    template<typename C> static char (&f(...))[2]; 

    static bool const value = sizeof(f<Derived>(0)) == 2;
}; 

struct A { 
  void x()
  {
  }
};
struct B { int X; };

int main() { 
    std::cout << HasX<A>::value << std::endl; // 1
    std::cout << HasX<B>::value << std::endl; // 0
}

(请注意,在第二个示例中,int x 中的 A 被成员函数 void x() 替换)。

我不知道如何解决这个问题。我通过执行类似的操作部分修复了此问题

template <bool, typename> class my_helper_class;

template <typename ctype> class my_helper_class <true, ctype>
{
  static bool const value = std :: is_member_object_pointer <decltype(&ctype :: x)> :: value;
};

template <typename ctype> class my_helper_class <false, ctype>
{
  static bool const value = false;
};

template <typename T> struct HasX
{
// ...

static bool const value = my_helper_class <sizeof(f <Derived>(0)) == 2, T> :: value;
};

这实际上选择我是否正在使用对象。但是,如果有更多同名重载函数 x ,则上述方法不起作用在我的类里面。

例如,如果我这样做

struct A
{
   void x()
   {
   }

   void x(int)
   {
   }
};

然后指针未成功解析并且调用 HasX <A>无法编译。

我该怎么办?有没有任何解决方法或更简单的方法来完成此任务?

最佳答案

问题是 HasX只检查名称 x存在。 ...如果 &C::x 则被选中是不明确(如果它同时匹配 FallbackT ,就会发生这种情况)。 ChT<>仅当 &C::x 时才选择重载正是Fallback::x 。我们从来没有真正检查 T::x 的类型- 所以我们从来没有真正检查 x 是否是一个变量或函数或其他什么。

解决方案是:使用 C++11 并检查 &T::x是一个成员对象指针:

template <class T, class = void>
struct HasX
: std::false_type
{ };

template <class T>
struct HasX<T,
    std::enable_if_t<
        std::is_member_object_pointer<decltype(&T::x)>::value>
    >
: std::true_type { };

如果&T::x不存在,替换失败,我们回退到主模板并得到 false_type 。如果&T::x存在,但名称重载,替换失败。如果&T::x存在,但为非重载函数,enable_if_t<false> 上替换失败。 SFINAE 为胜利而战。

这适用于所有这些类型:

struct A { 
  void x()
  {
  }

  void x(int)
  {
  }
};

struct B { int X; };
struct C { int x; };
struct D { char x; };

int main() { 
    static_assert(!HasX<A>::value, "!");
    static_assert(!HasX<B>::value, "!");
    static_assert(HasX<C>::value, "!");
    static_assert(HasX<D>::value, "!");
}

关于c++ - 如何检测类中是否确实存在特定的成员变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36603821/

相关文章:

java - 访问函数内部的变量

c++ - QDialog如何返回数据?

c++ - 在二叉树中插入 4 或 5 个数字,但在输出中只得到 3 个数字

c++ - 多个类型名的部分模板特化

c++ - 模板中的嵌套类型名称

c++ - 二进制表达式 ('std::ostream'(又名 'basic_ostream<char>')和 'const std::vector<int>' 的无效操作数)

c++ - 仅在多核上运行时出现段错误

c++ - 如何启用父级和派生的_shared_from_this

javascript - 奇怪的 JavaScript 行为,在调用转换器函数之前变量更改值

java - 变量未初始化