"unprotect" static const 成员有通用的方法吗?
Is there a generic way to "unprotect" static const members?
有时我会遇到这样一种情况,我得到一个 class(无法修改),它具有受保护的静态成员,例如
struct foo {
protected:
static const int x = 42;
static const int y = 101;
static const int z = 404;
// ... and more ...
};
不幸的是,我需要访问这些成员,而不是在派生的 class 中,而是在其他代码中。我写了这个:
struct bar : foo {
static const int x = foo::x;
static const int y = foo::y;
static const int z = foo::z;
};
但感觉比较笨拙。在 long 运行 class 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 declaration。您可以在 class 定义的上下文中使用 using
将成员从基础 class 导入派生的 class。如果 using
与您要导入的成员之一具有不同的访问规范,那么您实际上 "change" 在派生的 class.[= 的上下文中对该成员的访问规范。 14=]
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";
有时我会遇到这样一种情况,我得到一个 class(无法修改),它具有受保护的静态成员,例如
struct foo {
protected:
static const int x = 42;
static const int y = 101;
static const int z = 404;
// ... and more ...
};
不幸的是,我需要访问这些成员,而不是在派生的 class 中,而是在其他代码中。我写了这个:
struct bar : foo {
static const int x = foo::x;
static const int y = foo::y;
static const int z = foo::z;
};
但感觉比较笨拙。在 long 运行 class 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 declaration。您可以在 class 定义的上下文中使用 using
将成员从基础 class 导入派生的 class。如果 using
与您要导入的成员之一具有不同的访问规范,那么您实际上 "change" 在派生的 class.[= 的上下文中对该成员的访问规范。 14=]
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";