重新解释模板参数常量的 C++ 编译器行为
C++ Compiler behavior with re-interpreting template parameter constants
在处理 RAII 风格的守卫对象时,我最终在模板参数中编码了一些守卫状态。这似乎是合理的,例如,如果您想要一个递归/嵌套的保护对象,该对象知道它有多少层深度但没有 space 开销(我知道这是迂腐的)或消除一些运行时开销。不过,这变成了一种学术上的好奇心...
像这样的例子:
template <unsigned depth>
class guard {
unsigned get_depth() const {return depth;}
};
guard<2> g2;
std::cout << reinterpret_cast< guard<5>* >( &g2 )->get_depth(); // works? crazy? useful?
我一辈子都想不出这样做的正当理由,但它让我思考这是否是合法的 C++ 以及编译器应该如何处理这样的事情(如果它可以的话)或如果它只是彻头彻尾的愚蠢。
我假设因为在编译时需要知道转换目标,所以为转换实例化了相关模板。有没有人发现这样有用的东西,假设它确实有效并且有用途,如果是的话,它可以在哪里使用?
我猜的一般问题是 可以 reinterpret_cast
改变常量模板参数吗? 如果是这样,这只是一个类型 hack(因为需要更好的术语)和 g2
在这种情况下会 always return 2
(铸造后)?还是应该 return 5
(铸造后)?
这是未定义的,但不是因为严格的别名规则。对 get_depth
的调用既不读取也不修改任何对象的值(模板非类型参数不是对象),因此它不会 access (定义为在 [defns.access]) 严格别名规则含义内的任何内容。
这由 [class.mfct.non-static]/2 控制:
If a non-static member function of a class X
is called for an object
that is not of type X
, or of a type derived from X
, the behavior is
undefined.
在处理 RAII 风格的守卫对象时,我最终在模板参数中编码了一些守卫状态。这似乎是合理的,例如,如果您想要一个递归/嵌套的保护对象,该对象知道它有多少层深度但没有 space 开销(我知道这是迂腐的)或消除一些运行时开销。不过,这变成了一种学术上的好奇心...
像这样的例子:
template <unsigned depth>
class guard {
unsigned get_depth() const {return depth;}
};
guard<2> g2;
std::cout << reinterpret_cast< guard<5>* >( &g2 )->get_depth(); // works? crazy? useful?
我一辈子都想不出这样做的正当理由,但它让我思考这是否是合法的 C++ 以及编译器应该如何处理这样的事情(如果它可以的话)或如果它只是彻头彻尾的愚蠢。
我假设因为在编译时需要知道转换目标,所以为转换实例化了相关模板。有没有人发现这样有用的东西,假设它确实有效并且有用途,如果是的话,它可以在哪里使用?
我猜的一般问题是 可以 reinterpret_cast
改变常量模板参数吗? 如果是这样,这只是一个类型 hack(因为需要更好的术语)和 g2
在这种情况下会 always return 2
(铸造后)?还是应该 return 5
(铸造后)?
这是未定义的,但不是因为严格的别名规则。对 get_depth
的调用既不读取也不修改任何对象的值(模板非类型参数不是对象),因此它不会 access (定义为在 [defns.access]) 严格别名规则含义内的任何内容。
这由 [class.mfct.non-static]/2 控制:
If a non-static member function of a class
X
is called for an object that is not of typeX
, or of a type derived fromX
, the behavior is undefined.