最近,我一直在玩 C++20 的新
constexpr std::vector
(我使用的是 GCC v12),并且遇到了一个小问题(这实际上是 我的上一个问题的扩展,但我认为制作一个新的会更好)。我一直在尝试使用 constexpr std::vector
作为类的成员,但这似乎不起作用,因为你不能用 constexpr
注释它们,因此 constexpr
函数认为它们无法在编译时评估时间,所以现在我尝试使用模板参数,如下所示:
#include <array>
template<int N, std::array<int, N> arr = {1}>
class Test
{
public:
constexpr int doSomething()
{
constexpr const int value = arr[0];
return value * 100;
}
};
int main()
{
Test<10> myTestClass;
// return the value to prevent it from being optimized away
return myTestClass.doSomething();
}
这会产生预期的汇编输出(只是从 main 返回 100):
main:
mov eax, 100
ret
但是,这样的方法对
std::vector
不起作用,即使它们现在可以是 constexpr
!
#include <vector>
template<std::vector<int> vec = {1}>
class Test
{
public:
constexpr int doSomething()
{
constexpr const int value = vec[0];
return value * 100;
}
};
int main()
{
Test<> myTestClass;
return myTestClass.doSomething();
}
这会引发此错误:
<source>:3:35: error: 'std::vector<int>' is not a valid type for a template non-type parameter because it is not structural
3 | template<std::vector<int> vec = {1}>
| ^
In file included from /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/vector:64,
from <source>:1:
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/stl_vector.h:423:11: note: base class 'std::_Vector_base<int, std::allocator<int> >' is not public
423 | class vector : protected _Vector_base<_Tp, _Alloc>
| ^~~~~~
<source>: In function 'int main()':
<source>:17:24: error: request for member 'doSomething' in 'myTestClass', which is of non-class type 'int'
17 | return myTestClass.doSomething();
我怎样才能用
vector
做到这一点,或者甚至可能吗?还有,是否可以成为constexpr
会员?
您仍然(在 C++20 中,我认为 C++23 没有任何变化)不能使用
std::vector
作为非类型模板参数或将任何 std::vector
变量标记为 constexpr
或有任何常量表达式导致 std::vector
作为值。
C++20 中现在允许而以前不允许的唯一用例是拥有一个(非
constexpr
)std::vector
变量或对象,该变量或对象是在常量表达式在求值和销毁之前构造的。持续评估结束。
这意味着您现在可以使用该功能
constexpr int f() {
std::vector<int> vec;
vec.push_back(3);
vec.push_back(1);
vec.push_back(2);
std::sort(vec.begin(), vec.end());
return vec.front();
}
在其上添加
constexpr
并在常量表达式中使用它,例如
static_assert(f() == 1);
但仅此而已。它仍然非常有用,因为在此之前您只能使用不需要任何动态内存分配的算法来在编译时计算某些内容。这意味着您通常不能直接在编译时上下文中使用通常的运行时算法/实现。
对于任何保留动态分配内存引用的类型也是如此。您需要在常量表达式求值期间销毁它们,即它们必须是函数中的临时变量或局部变量,或者返回不存储在运行时上下文中的值。
在非类型模板参数的特定情况下,情况甚至更加严格。并非所有可以创建
constexpr
变量的类型都可以用作非类型模板参数。有更严格的限制。它们一定是所谓的结构类型。
这些例如是基本类型,如算术类型、指针等。如果类类型是文字类型,则它是结构类型,并且仅具有非静态数据成员,即
public
和非静态数据成员。 mutable
以及所有这些,递归地,结构类型。
我认为很明显
std::vector
不满足这些要求。 std::array
被明确指定为 结构类型,这就是为什么您可以将其用作非类型模板参数。