C++ 模板怎么可能有一个非静态非类型参数?

问题描述 投票:0回答:3

C++ 模板是编译时构造。在 C++20 中,模板函数怎么可能用非静态对象实例化?

struct X {};
template<typename T, X x> auto f() {
    return x;
}

int main() {
    auto x = X{};
    f<double, x>();
}
c++ templates c++20
3个回答
1
投票

参数必须在编译时完全可用。

如果类型

X
中有非静态数据成员,则上述示例不可用:

struct X { 
   int  value;  // <<==== added this
};
template<typename T, X x> auto f() {
    return x;
}

int main() {
    auto x = X{};
    f<double, x>();
}

要投诉了

<source>:8:17: error: the value of 'x' is not usable in a constant expression
    8 |     f<double, x>();
      |     ~~~~~~~~~~~~^~
<source>:7:10: note: 'x' was not declared 'constexpr'
    7 |     auto x = X{};
      |          ^

要解决这个问题,您必须将

x
声明为 constexpr

struct X { 
    int  value; 
};
template<typename T, X x> auto f() {
    return x;
}

int main() {
    constexpr auto x = X{3};
    f<double, x>();
}

https://godbolt.org/z/f56nb1Ped

现在想象一下,这类似于传递一个整数作为模板参数。


template< size_t N >
struct CharT {
   char data[N];
};

0
投票

它是否是静态的并不重要,重要的是它是否在编译时可用。

x
由于其定义方式,因此在编译时可用。您可以在
constexpr
下阅读更多相关信息(对于函数,
consteval
)。


0
投票

注意

x
变量本身 not 什么成为模板参数。模板参数被声明为一个值,所以
f<double, x>()
实际上copys(在编译时)
x
形成模板参数的值。也就是说,作为模板参数的转换表达式包括通过聚合初始化的copy。这与调用原型函数
void f(X x)
相同。 C++ 具有值语义!

在评估

foo<double, x>()
中的模板参数时,不允许从x中读取
。 (更准确地说,
x
 是类类型,“读取”没有意义;读取标量子对象是非法的——“原语”,如 
int
s、
float
s 等,在 
X
 中的字段。)但是,在这种情况下,
X
 中没有字段,因此复制 
x
 以形成模板参数 
不需要读取 x
。所以不需要发生任何违法行为! 
foo<double, x>()
 编译成功,因为模板参数值可以在不做任何非常量的情况下确定。 (特别注意,在常量表达式中允许形成对非
constexpr
变量
的引用。)

注意以下内容也可以编译。同样,重要的是

foo<double, x>

要求
x
copied。在这里,用户指定的复制构造函数实际上并没有读取x
,因此代码可以编译。但是默认的复制构造函数将从 
x
 读取,并且使用该构造函数会使代码无法编译。

struct X { int i; constexpr X() : i(0) { } constexpr X(X const&) : X() { } // (1) does not read source object! // if (1) is commented out, the call to foo will fail to compile // the compiler-generated copy constructor if (1) is commented out is effectively // constexpr X(X const &x) : i(x.i) { } }; int main() { X x; foo<double, x>(); // ^ as a converted expressions *includes a call to the copy constructor*, and that call is indeed a constant expression! }
最后,请注意 

static

 只需要在常量表达式中
获取地址/形成对对象的引用。查看对象的value并不要求它是静态的。

© www.soinside.com 2019 - 2024. All rights reserved.