T 不是非类型模板参数的有效类型

T is not a valid type for non-type template parameter

提问人:Alexey Starinsky 提问时间:11/18/2023 更新时间:11/18/2023 访问量:57

问:

无法编译以下代码:

#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;

template <class T, class ReturnType>
class func_getter
{
public:

    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)();
    }

private:

    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;
    }

    // All the code above compiles, but the code below does not.

    {
        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;
}

MSVC 2022 错误:

error C2993: 'Getter': is not a valid type for non-type template parameter 'state'
C++语言

评论

1赞 user12002570 11/18/2023
基本上是它有一个私有成员,所以它不能用作非类型模板参数。Getterfunc_getter<A, int>
0赞 Alexey Starinsky 11/18/2023
@user12002570奇怪的是,std::array 的数据成员是公共的。
1赞 user12002570 11/18/2023
是的,it() 需要成为聚合。std::array
0赞 Caleth 11/18/2023
公开数据并不特别奇怪,它意味着作为 C 样式数组的直接替代品。 同样暴露它std::arraystd::array::data()

答:

4赞 user12002570 11/18/2023 #1

问题是 (aka ) 不是结构类型,因此它不能用作 temp.param 的非类型模板参数:Getterfunc_getter<A, int>

  1. 非类型模板参数应具有以下类型之一(可能是 cv 限定的):
  • 结构类型(见下文),
  1. 结构类型是以下类型之一
  • 具有以下属性的文本类类型:
    • 所有基类和非静态数据成员都是公共的、不可变的,并且

(强调我的)

并且由于具有私有非静态数据成员,因此它违反了上述规则,因此不是结构类型,不能用作非类型模板参数。Getterm_p

3赞 Jean-Baptiste Yunès 11/18/2023 #2

完整的错误是:

template <class T, T state>
                     ^
pp.cpp:65:9: note: while substituting prior template arguments into non-type template parameter 'state' [with T = func_getter<A, int>]
        stateless<Getter, g> s;
        ^~~~~~~~~~~~~~~~~~~~
pp.cpp:44:15: note: 'func_getter<A, int>' is not a structural type because it has a non-static data member that is not public
    MyFuncPtr m_p;

重要的一点是“func_getter<A,int>”不是结构类型。 结构类型不能有私有字段。

2赞 Caleth 11/18/2023 #3

G++ 的错误消息在这里更有用:

error: 'func_getter<A, int>' 不是模板非类型参数的有效类型,因为它不是结构化的。

cppreference 列出要求

非类型模板参数必须具有结构类型,该类型是以下类型之一(可选 cv 限定,将忽略限定符):

  • 左值引用类型(对象或函数);
  • 整数类型;
  • 指针类型(指向对象或函数);
  • 指向成员类型(成员对象或成员函数)的指针;
  • 枚举类型;
  • std::nullptr_t;
  • 浮点类型;
  • 具有以下属性的文本类类型:
    • 所有基类和非静态数据成员都是公共的、不可变的,并且
    • 所有基类和非静态数据成员的类型都是结构类型或(可能是多维)数组。

即问题是.MyFuncPtr m_p;private

见 coliru