如何检测类中是否存在特定的PRIVATE成员变量?

Use*_*645 4 c++ friend template-meta-programming constexpr

这个问题是基于这篇文章

目标:我想知道一个类是否有成员变量x。我想收到true无论此变量是否为privatepublicprotected

方法:如果类有成员变量,您可以使用以下代码获取信息:


template <typename T, typename = int>
struct HasX : std::false_type { };

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

使用它

if constexpr (HasX<my_class>::value) {
   // do stuff with x
} else {
   // ...
}
Run Code Online (Sandbox Code Playgroud)

上面的代码在这种情况下不起作用

struct my_class {
private:
   int x;
};
Run Code Online (Sandbox Code Playgroud)

我怎样才能使这项工作?我想HasX<my_class>::valuetrue

想法:

使用friend可以访问T::x. 这似乎不起作用。看看这个活生生的例子

max*_*x66 5

嗯......不确定这个解决方案的正确性和局限性......但是......

如果您定义了一个具有x可访问元素的辅助结构

struct check_x_helper
 { int x; };
Run Code Online (Sandbox Code Playgroud)

您可以编写一个模板结构,该结构继承自check_x_helper您想要查看的类是否包含x成员

template <typename T>
struct check_x : public T, check_x_helper
Run Code Online (Sandbox Code Playgroud)

在里面check_x你可以声明(仅声明:在 a 中使用decltype())如下

template <typename U = check_x, typename = decltype(U::x)>
static constexpr std::false_type check (int);

static constexpr std::true_type check (long);
Run Code Online (Sandbox Code Playgroud)

观察第一个,模板一个:当被检查的类(T)包含一个x成员时, thedecltype(U::x)是不明确的,因为它x是从Tand继承的check_x_helper,所以这个函数被 SFINAE 丢弃。

相反,当T不包含x成员时,没有歧义,decltype(U::x)check_x_helper::x( int)的类型,第一个check()函数保持启用状态。

现在你需要一些东西

using type = decltype(check(0));

static constexpr auto value = type::value;
Run Code Online (Sandbox Code Playgroud)

调用check(0)int参数表示对模板版本的偏好)并将检测到的保存valuestatic constexpr变量中。

下面是一个完整的编译示例

#include <iostream>
#include <utility>

class foo
 { int x; };

struct bar
 { };

struct check_x_helper
 { int x; };

template <typename T>
struct check_x : public T, check_x_helper
 {
   template <typename U = check_x, typename = decltype(U::x)>
   static constexpr std::false_type check (int);

   static constexpr std::true_type check (long);

   using type = decltype(check(0));

   static constexpr auto value = type::value;
 };

int main()
 {
   std::cout << check_x<foo>::value << std::endl;
   std::cout << check_x<bar>::value << std::endl;
 }
Run Code Online (Sandbox Code Playgroud)

此解决方案的缺点:decltype(U::x)T声明x为方法或using类型时也会失败(歧义)。所以给出

class foo
 { int x () { return 0;} ; };
Run Code Online (Sandbox Code Playgroud)

或者

class foo
 { using x = int; };
Run Code Online (Sandbox Code Playgroud)

check_x<foo>::value您那里获得1.

  • 惊人的解决方案!真的很喜欢! (2认同)