【发布时间】:2021-09-20 10:44:13
【问题描述】:
据我了解,C++11 明确指出 reinterpret_cast 不能在常量表达式中使用。原因(根据我的理解)是编译器无法解释转换的有效性。话虽如此,似乎确实存在某种程度的诡计,即使在使用 reinterpret_cast 语句时也可以使函数编译。
我有一种情况,父类中的单个字节数组可以根据当时我希望数据表示的子类进行重新解释。
在代码中,我有一个constexpr,它返回对数组中子类成员变量表示形式的引用,在本例中为uint32_t 变量。使用reinterpret_cast<uint32_t&>() 代码不会与编译器一起编译,并声明reinterpret_cast 不能导致常量表达式。但是,我可以通过将函数包装在模板中或使用简单的三元表达式来编译代码。
下面的示例代码包含一个标记为compBranchSwitch 的宏,它允许您在编译场景之间快速切换,以方便使用。
#include <cstdint>
#include <cstddef>
#include <array>
#include <iostream>
#define compBranchSwitch 0 //Switch to determine which branch to compile: 2 - With template function, 1 - With ternary operator, 0 - Without any trickery (should not compile)
struct Attributes {
static std::array<char, 4> membersArray;
struct Subclass {
uint32_t num;
static constexpr uint16_t offsetNum() { return offsetof(Subclass, num); }
#if compBranchSwitch == 2
template<bool nothing> //Unused template parameter that circumvents reinterpret_cast being unusable within a constexpr.
static constexpr uint32_t& LoadNum() { return reinterpret_cast<uint32_t&>(membersArray[offsetNum()]); }
#elif compBranchSwitch == 1
static constexpr uint32_t& LoadNum() { return (true ? reinterpret_cast<uint32_t&>(membersArray[offsetNum()]) : reinterpret_cast<uint32_t&>(membersArray[offsetNum()])); }
#else
static constexpr uint32_t& LoadNum() { return reinterpret_cast<uint32_t&>(membersArray[offsetNum()]); }
#endif
static inline void SaveNum(const uint32_t& newTest) { std::memcpy(&membersArray[offsetNum()], &newTest, sizeof(newTest)); }
};
};
std::array<char, 4> Attributes::membersArray;
void main() {
Attributes::Subclass::SaveNum(32);
#if compBranchSwitch == 2
std::cout << Attributes::Subclass::LoadNum<true>();
#else
std::cout << Attributes::Subclass::LoadNum();
#endif
}
我的问题是:
- 对于使用上述任何技巧来编译程序,我应该担心还是犹豫不决?
- 有没有更好的解决办法让
reinterpret_cast在常量表达式中工作? - 仅仅因为
reinterpret_cast不允许在常量表达式中使用,编译器是否仍可能在编译时在大量优化标志下对其进行评估?
如果有帮助,我将在 C++17 下编译并使用 Visual Studio。
关于 stackoverflow 的一篇密切相关的帖子我发现对于有关常量表达式的 C++11 草案和发现三元运算符技巧 can be found here 的信息很有帮助。
【问题讨论】:
-
所有这些花哨的技巧都可以让您将函数标记为
constexpr。但是您是否检查过是否可以在编译时调用它?我打赌不会。 -
@HolyBlackCat
num变量的值无法在编译时评估,因为membersArray不是常量。在编译时应该能够评估的是对membersArray中的num变量的引用或指针,这就是我要返回的内容。有没有一种简单的方法可以检查这是否在编译时真正被评估? -
@HolyBlackCat 正在执行的
membersArray是静态的,并且没有任何调用引用实例化对象。如果我将Attributes设为静态,会发生什么变化? -
抱歉,没注意到。那么是的,它不应该改变任何东西。一会儿我会发布一个正确的答案。
-
@Ryoku 那为什么不使用
std::variant:en.cppreference.com/w/cpp/utility/variant?
标签: c++ c++11 constexpr reinterpret-cast constant-expression