【发布时间】:2021-08-10 12:21:21
【问题描述】:
从elsewhere 我知道,在 C++17 中,如果没有立即初始化,就无法声明静态 constexpr 数据成员(尽管yet elsewhere 他们使用了这样的示例)。
// --- in header ---
struct Data{
LPCTSTR str;
int i;
};
class C{
public:
static constexpr Data MyData; // VS complains: this requires an in-class initializer
};
// --- in implementation file ---
constexpr Data C::MyData={
_T("Hi"), 12345
};
我的代码暂时还必须在较旧的 Visual Studio 中编译,因为缺少 constexpr 概念很容易被#定义为
#if _MSC_VER<=1600 // pre-C++11 compiler?
#define constexpr const
#endif
突然之间,代码库几乎可以兼容从 VS6 到 VS2019 的任何东西。如果通过 Visual Studio 中的某些隐藏命令行开关允许类外初始化,请纠正我。
所以我想出了一个解决方法,我不确定它的有效性。与数据成员不同,静态 constexpr 方法不必具有类内主体。所以我这样做:
// --- in header ---
struct Data{
LPCTSTR str;
int i;
};
class C{
public:
static constexpr Data GetMyData();
};
// --- in implementation file ---
constexpr Data C::GetMyData(){
constexpr Data D={
_T("Hi"), 12345
};
return D;
}
然后我可以从 constexpr 中受益,但仍然可以在旧版 Visual Studio 下编译(借助上述 #define):
constexpr LPCTSTR Greeting=C::GetMyData().str;
并且还出人意料地在运行时获取返回对象的地址:
const Data *p=&C::GetMyData();
const LPCTSTR greeting=p->str;
这在我的应用程序中很棒而且很受欢迎!但是让我担心我收到的什么的地址?它是编译到生成的可执行文件中的对象的地址(并且在运行时驻留在受保护的内存中)还是在运行时真正创建的全局变量的地址?我当然希望在较新的 Visual Studios 下编译时出现更早的情况,而我不在乎 C++11 之前的版本下的情况。
提前致谢。
【问题讨论】:
-
const Data *p=&C::GetMyData();是一个危险的指针。 GCC 甚至不会编译这段代码。 MS编译器accepts它作为语言扩展。 -
拥有一个未知值的编译时间常数有什么意义?
-
你应该有一些宏
CONSTEXPR而不是#define constexpr const。constexpr和const不可互换。例如:constexpr int& C::get()和const int& C::get()。 -
@Evg 我虽然是这样,但最好问! :-(
标签: c++ optimization compile-time-constant