有没有一种通用方法来"unprotect"静态常量成员?

Is there a generic way to "unprotect" static const members?

本文关键字:unprotect 静态 常量 成员 方法 一种 有没有      更新时间:2023-10-16

有时我面临一个具有受保护静态成员的类(无法修改(的情况,例如

struct foo {
protected:
    static const int x = 42;
    static const int y = 101;
    static const int z = 404;
    // ... and more ...
};

不幸的是,我需要访问这些成员,不是在派生类中,而是在其他代码中。我写了这个:

struct bar : foo {
    static const int x = foo::x;
    static const int y = foo::y;
    static const int z = foo::z;
};

但感觉相当笨拙。从长远来看,应该修改类foo以提供对这些常量的访问,但只要不是这种情况,我就希望有更好的东西。我可以沿着以下行编写一个宏

int x = SOME_MACRO_VOODOO(foo,x);

不过,我想知道是否有办法避免宏。我尝试了很多方法,例如这个

struct f {
    protected:
    static const int x = 42;
};
template <typename T, int T::*P>
struct bar : f {
    int get_value() { return this->*P;}
};
int main() {
    bar<f,&f::x>().get_value();
}

失败,因为&f::x不是指向成员的指针,而只是一个int *,当然f::x不可访问:

prog.cc: In function 'int main()':
prog.cc:12:16: error: could not convert template argument '& f::x' from 'const int*' to 'int f::*'
     bar<f,&f::x>().get_value();
                ^
prog.cc:12:5: error: 'const int f::x' is protected within this context
     bar<f,&f::x>().get_value();
     ^~~~~~~~~~~~
prog.cc:3:22: note: declared protected here
     static const int x = 42;

听起来你正在寻找一个使用声明。可以在类定义的上下文中使用using将成员从基类导入派生类。如果using与要导入的成员之一具有不同的访问规范,则可以在派生类的上下文中有效地"更改"该成员的访问规范。

struct foo {
protected:
    static const int x = 42;
    static const int y = 101;
    static const int z = 404;
    // ... and more ...
};

struct bar : foo {
    using foo::x;
    using foo::y;
    using foo::z;
};
int main()
{
    // Should work fine
    int a = bar::x;
}
#define BYPASS_STATIC_PROTECTED( CLASS, FIELD ) 
  []()->decltype(auto){ struct cheater:CLASS { using CLASS::FIELD; }; return cheater::FIELD; }()
auto x= BYPASS_STATIC_PROTECTED( foo, x );

我们也可以在成员字段上执行此操作:

template<class T>
struct tag_t { using type=T; };
#define BYPASS_MEMPTR_PROTECTED_HELPER( FIELD ) 
  [](auto tag){ using T=typename decltype(tag)::type; struct cheater:T { using T::FIELD; }; return &cheater::FIELD; }
#define BYPASS_MEMPTR_PROTECTED( CLASS, FIELD ) 
  BYPASS_MEMPTR_PROTECTED_HELPER(FIELD)(tag_t<CLASS>{})
#define BYPASS_PROTECTED_ON_MEMBER( FIELD ) 
  [](auto& obj )->decltype(auto) { 
    using T = std::decay_t<decltype(obj)>; 
    return obj.* BYPASS_MEMPTR_PROTECTED_HELPER( FIELD )(tag_t<T>{}); 
  }

以及类似的成员函数:

#define BYPASS_PROTECTED_ON_METHOD( MEMBER ) 
  [](auto& obj, auto&&...args )->decltype(auto) { 
    using T = std::decay_t<decltype(obj)>; 
    return (obj.* BYPASS_MEMPTR_PROTECTED_HELPER( MEMBER )(tag_t<T>{}))( decltype(args)(args)... ); 
  }

活生生的例子。

测试代码:

struct foo {
protected:
    static const int x = 42;
    static const int y = 101;
    static const int z = 404;
    // ... and more ...
    int member = 7;
    int method(int v) const { return -v; }
};
std::cout << BYPASS_STATIC_PROTECTED( foo, x ) << "n";
std::cout << BYPASS_PROTECTED_ON_MEMBER( member )( f ) << "n";
std::cout << BYPASS_PROTECTED_ON_METHOD( method )( f, 1 ) << "n";