You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何构造可赋值给constexpr变量的含tuple向量的C++23类?

编译期实例化包含tuple向量的C++23类问题

你想要构造一个能在编译期实例化、包含tuple向量的类,但现有代码在C++23下编译失败。以下是你的最小可复现代码:

#include <vector>
#include <tuple>

template<typename... Ts>
class vector_of_tuple {
public:
   constexpr vector_of_tuple( const std::tuple<Ts...> & value ) : samples( 1, value ) {};
private:
   std::vector<std::tuple<Ts...>> samples;
};

constexpr std::tuple<int,long,int> tuple_v = std::make_tuple(1,2,3);
// 添加constexpr修饰时编译报错
constexpr vector_of_tuple<int,long,int> vector_of_tuple_v(tuple_v);

编译报错信息:

constexpr变量‘vector_of_tuple_v’的类型‘const vector_of_tuple<int, long int, int>’不是字面类型
‘vector_of_tuple<int, long int, int>’不是字面类型的原因:
非静态数据成员‘vector_of_tuple<int, long int, int>::samples’具有非字面类型
‘std::vector<std::tuple<int, long int, int>, std::allocator<std::tuple<int, long int, int> > >’不是字面类型的原因:
‘std::vector<std::tuple<int, long int, int>, std::allocator<std::tuple<int, long int, int> > >’没有constexpr析构函数

问题根源

虽然C23为std::vector添加了大量constexpr成员函数(比如构造、元素访问、修改等),但**std::vector的析构函数直到C26才被标记为constexpr。而constexpr变量要求其类型是字面类型**,字面类型的核心条件之一是类必须拥有constexpr析构函数——这就是代码编译失败的核心原因。

解决方案

1. 改用std::array(固定大小场景)

如果编译期能确定容器的元素数量,std::array是完全符合字面类型要求的替代品,支持所有constexpr操作:

#include <array>
#include <tuple>

template<typename... Ts, std::size_t N = 1>
class array_of_tuple {
public:
    constexpr array_of_tuple(const std::tuple<Ts...>& value) 
        : samples{value} {}
private:
    std::array<std::tuple<Ts...>, N> samples;
};

constexpr std::tuple<int, long, int> tuple_v = std::make_tuple(1,2,3);
constexpr array_of_tuple<int, long, int> array_of_tuple_v(tuple_v);

2. 自定义编译期动态容器(可变大小场景)

如果需要编译期动态添加元素,可以自己实现一个基于固定缓冲区的constexpr容器,用std::array作为底层存储,跟踪实际元素数量:

#include <tuple>
#include <array>

template<typename... Ts, std::size_t MaxSize = 16>
class constexpr_tuple_vector {
public:
    constexpr constexpr_tuple_vector(const std::tuple<Ts...>& value) {
        push_back(value);
    }

    constexpr void push_back(const std::tuple<Ts...>& value) {
        // 超出最大容量时可触发编译错误,避免运行期问题
        static_assert(MaxSize > 0, "Max size must be positive");
        if (size_ >= MaxSize) {
            throw std::out_of_range("Exceed max container size");
        }
        data_[size_++] = value;
    }

    constexpr std::size_t size() const noexcept { return size_; }
    constexpr const std::tuple<Ts...>& operator[](std::size_t idx) const noexcept {
        return data_[idx];
    }

private:
    std::array<std::tuple<Ts...>, MaxSize> data_;
    std::size_t size_ = 0;
};

constexpr std::tuple<int, long, int> tuple_v = std::make_tuple(1,2,3);
constexpr constexpr_tuple_vector<int, long, int> vec_v(tuple_v);

3. 升级到C++26标准

如果项目可以切换到C26标准,原代码无需修改即可正常编译运行——因为C26正式将std::vector的析构函数标记为constexpr,使其成为字面类型。

内容的提问来源于stack exchange,提问作者SRH

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 11:37:34