C++17/20 - 固定大小容器类的类似数组的初始化

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

我有一个专门的模板化容器类,其中包含固定大小的数组(大小由模板定义):

template<typename T, std::size_t N>
class container {

protected:
T _arr[N];
std::size_t _size = 0;      // does not necessarily equal N
\* other members *\

public:
\* ctors and member functions *\
};

现在我想像 c 数组一样初始化其底层数组:

container c = { 1, 2, 3, 4 };

这行代码应将

_arr
初始化为包含
{ 1, 2, 3, 4 }
的整数数组。

同时我也希望能够使用其他构造函数。例如:

container c(size, value);     // initializes _arr until size with value

我的理想实现想法是将 (constexpr) 初始值设定项列表的大小传递给模板参数大小的方法。

我尝试过的:

1.使用以数组作为参数的构造函数:

container(const T (&arr)[N]) : _size(N) {
    std::copy(std::begin(arr), std::end(arr), _arr);
}

当直接在构造函数中使用它时,这是有效的:

container c({ 1, 2, 3, 4})
,但在使用复制构造时不起作用:
container c = {1, 2, 3, 4}
。在数组周围使用另一组花括号可以解决问题(
container c = {{1, 2, 3, 4}}
),但这不是我第一次设想这个类时所想的。

2.使用带有可变参数模板的构造函数

template<typename ...U, typename = std::enable_if<std::conjunction_v<std::is_same<T, U>...>> >
container(U... values) : _size(sizeof...(U)) {
    T a[] = {values...};
    std::move(std::begin(a), std::end(a), _arr);
}

以及类型推导指南:

template<typename ...T>
container(T...) -> container<std::common_type_t<T...>, sizeof...(T)>;

这是我得到的最接近的结果,但不幸的是它直接搞乱了构造函数的使用(

container c(size, value)
)。


我的理想实现想法是将初始化列表的大小作为模板参数传递(例如使用类型推导指南):

container(std::initializer_list<T> list) : _size(list.size()) {
    std::copy(std::begin(list), std::end(list), _arr);
}
template<typename L, 
         typename T = L::value_type, 
         typename = std::enable_if<std::is_same_v<L, std::initializer_list<T>>> >
container(L init_list) -> container<T, init_list.size()>;

这显然无法编译(

error: template argument 2 is invalid
)。

有没有办法实现这一点,最好是用 constexpr 方式?

c++ templates containers c++20 list-initialization
1个回答
0
投票

您所拥有的类似于

inplace_vector
/
static_vector
。他们深思熟虑并选择支持 CTAD,正是因为最大容量不容易推论。

但是,如果您的用例是初始大小通常是最大大小,则可以混合使用选项 2 和 3。您无法在编译时获取

initializer_list
参数的大小,但可以通过推导指南不必对应于构造函数。你可以做这样的事情:

template<typename T, std::size_t N>
class container {
    // ...
    // initializer_list constructor, like in (3)
    container(std::initializer_list<T> list) : _size(list.size()) {
        std::copy(std::begin(list), std::end(list), _arr);
    }
};

// Parameter pack deduction guide, like in (2)
template<typename... T>
container(T...) -> container<std::common_type_t<T...>, sizeof...(T)>;

container c{1, 2, 3};
// container<int, 3> deduced from deduction guide, initializer_list<int> constructor used
© www.soinside.com 2019 - 2024. All rights reserved.