C++的模板可以接受非类型参数,也就是接受一个值作为参数。但是能够接受的范围有限,基本上局限在具有内部链接属性的值,集中在整型值,比如各种整数,以及也为整型的指针值。

p0732r0也就是Class Types in Non-Type Template Parameters - Open-Std.oRg提倡让模板非类型参数可以接受类实例。这个特性已经进入C++20。

p0732r0中举的例子,跟David Vandevoorde在How do you pass a string literal as a parameter to a C++ template class?的回答采用的例子相同。都是展示如何以类实例作为非类型参数传给模板。

David举的例子:

    template<FixedString str> struct X {
    };

    #include <compare>
    #include <algorithm>
    template<int N> struct FixedString {
      constexpr FixedString(char const (&s)[N]) {
        std::copy_n(s, N, this->elems);
      }
     
      constexpr std::strong_equality
         operator<=>(FixedString const&) const = default;
      char elems[N];
    };

    template<int N> FixedString(char const(&)[N])->FixedString<N>;

除了传类实例给模板以外,上面的代码还用到了飞船运算符<=>这个C++20的特性,用来自动生成强对等性的比较方法。

有了FixedString的定义,你可以写出这样的代码:

    FixedString msg("a message");

C++17引入了模板参数自动推导功能,所以不用显示写FixedString<10>。因此,你也可以写:

    X<"a message"> x;

编译器会自动推导出X<“a message”>其实是X<FixedString<10>>

David还提到很多草案细节,这边就不赘述了。

Named Template Arguments一文的作者举了另外一些例子,可能更简单一点:

struct Point {
   int x = 0;
   int y = 0;
};

template <Point> // ok in C++20
void takes_tmpl_point();

takes_tmpl_point<{.x=1, .y=2}>(); // x=1, y=2
takes_tmpl_point<{.y=3}>();       // x=0, y=3
takes_tmpl_point<{.x=4}>();       // x=4, y=0
takes_tmpl_point<{.y=5, .x=6}>(); // ill-formed

这样看起来,是不是更清爽一点?

cppreference: Template parameters and template arguments所提到C++20对非类型模板参数的改进:

    a floating-point type;
    a literal class type with the following properties: 

        all base classes and non-static data members are public and non-mutable and
        the types of all bases classes and non-static data members are structural types or (possibly multi-dimensional) array thereof. 

其他

(本篇完)