为何在VS2015中使用constexpr类成员变量报错?
首先,你遇到的报错原因是Visual Studio 2015的MSVC编译器对C++11标准中constexpr非静态数据成员的支持存在局限性。在C++11里,虽然标准允许字面值类型的constexpr非静态成员在类内初始化,但VS2015的编译器(版本19.0)并没有完全实现这一特性,所以会抛出'constexpr' is not valid here的错误。
另外,从你的需求来看,你实际需要的是与类类型无关的、可在头文件中初始化的const static变量,而非非静态的constexpr成员——你的代码写法和实际需求不匹配,这也是导致问题的一个关键点。
针对需求的解决方案
根据你后续要将类改为模板、且常量与模板类型无关的需求,这里提供几种可行的方案:
方案1:使用const static成员(兼容C++11和VS2015)
对于整数类型的静态常量,C++11允许直接在类内初始化,不需要在cpp文件中单独定义(除非你需要取该变量的地址)。代码示例:
class myClass { public: const static int x = 4; // 类内直接初始化,头文件中即可使用 };
如果后续改成模板类,这个静态常量依然可以保留在类内,因为它和模板参数无关:
template<typename T> class myTemplateClass { public: const static int x = 4; // 不受模板参数T影响 };
VS2015对这种写法完全支持,不会出现编译错误。
方案2:将常量移至独立命名空间(更灵活,适合与类无关的常量)
如果这个常量本质上和类没有强关联,只是类需要使用它,你可以把它放在一个命名空间里,这样无论是普通类还是模板类都能直接访问:
namespace MyConstants { constexpr int x = 4; // constexpr在这里可以正常使用,VS2015支持命名空间内的constexpr } class myClass { // 使用时直接引用MyConstants::x }; template<typename T> class myTemplateClass { // 同样可以用MyConstants::x };
这种方式的好处是常量的作用域更清晰,后续如果其他类也需要使用这个常量,直接引用命名空间即可。
方案3:使用constexpr static成员(C++14风格,VS2015部分支持)
如果你想使用constexpr来强调常量的编译期特性,C++14允许constexpr static成员在类内直接初始化。VS2015对这种写法的支持是可行的,代码示例:
class myClass { public: constexpr static int x = 4; }; template<typename T> class myTemplateClass { public: constexpr static int x = 4; };
注意:如果需要取这个constexpr static成员的地址,你还是需要在cpp文件中补充定义(即使是模板类,也可以在cpp里显式实例化时定义),不过如果只是作为常量值使用,类内初始化就足够了。
总结
你的核心问题是VS2015不支持C++11的非静态constexpr成员,同时你的代码写法和实际需求(静态常量)不匹配。选择上面的任意一种方案,都能解决你的编译错误,同时满足后续模板类的需求。
内容的提问来源于stack exchange,提问作者mans

