MSVC 2022编译报错:Getter并非非类型模板参数的有效类型
非类型模板参数编译错误分析与解决
问题描述
给定代码中,stateless<Array, a>和stateless<A, a>可以正常编译,但使用func_getter作为非类型模板参数时,MSVC 2022报错:
error C2993: 'Getter': is not a valid type for non-type template parameter 'state'
错误原因
C++标准对非类型模板参数的类型有严格限制:只有结构类型(structural type)的constexpr对象才能作为非类型模板参数传递。
结构类型需满足以下全部条件:
- 是标量类型(如int、指针、成员指针),或
- 是类类型且满足:
- 所有非静态数据成员为公共访问权限
- 无用户声明的析构函数
- 无私有/保护的非静态数据成员
- 无基类
- 无虚函数
- 所有非静态数据成员的类型都是结构类型或结构类型的数组
你的func_getter类包含私有成员m_p,违反了"所有非静态数据成员为公共访问权限"的要求,因此不属于结构类型,无法作为非类型模板参数的类型。
而std::array和struct A都是结构类型:
std::array的内部成员符合标准规定的公共访问要求struct A的x是公共成员,无私有/保护成员,满足结构类型条件
解决方案
调整func_getter的定义,使其符合结构类型要求,最简单的方式是将成员设为公共访问权限:
#include <array> template <class T, T state> class stateless { public: void f() { /* do something with m_val*/; } private: static inline constexpr T m_val = state; }; struct A { int x; int GetX() const { return x; } }; template <class T, class ReturnType> using FuncPtr = ReturnType(T::*)() const; // 改为struct(默认成员public),或显式将m_p设为public template <class T, class ReturnType> struct func_getter { using object_type = T; using value_type = ReturnType; using MyFuncPtr = FuncPtr<T, ReturnType>; constexpr func_getter(MyFuncPtr p) : m_p(p) {} constexpr ReturnType operator() (const T& val) const { return (val.*m_p)(); } MyFuncPtr m_p; // 公共成员 }; int main() { { using Array = std::array<int, 3>; constexpr std::array<int, 3> a = { 1, 2, 3 }; stateless<Array, a> s; } { constexpr A a = { 1 }; stateless<A, a> s; } { using Getter = func_getter<A, int>; constexpr Getter g(&A::GetX); stateless<Getter, g> s; // 编译通过 } { constexpr func_getter g(&A::GetX); stateless<decltype(g), g> s; // 编译通过 } return 0; }
修改说明
- 将
func_getter从class改为struct,利用struct默认的公共成员访问权限;也可以保留class,但显式给m_p加上public修饰符。 - 修改后
func_getter满足结构类型的所有要求,其constexpr实例即可作为非类型模板参数传递。
内容的提问来源于stack exchange,提问作者Alexey Starinsky
相关产品推荐
相关产品推荐

