使用初始化列表初始化数组/将初始化列表转换为参数包

5
我需要使用初始化列表初始化编译时大小的类数组。我已经知道可以使用参数包构造函数并即时初始化,但在这种情况下我需要使用初始化列表。如果可能的话,我也想避免动态初始化数组。以下是伪代码:
template<typename Type, std::size_t Length>
class Test
{
    public:
        Test(const std::initializer_list<Type> args)
        :   m_tData(args) //<-- Doesn't work of course
        {}

    private:
        Type m_tData[Length];
};

当然,对于非 const 类型,我可以执行:
Test(const std::initializer_list<Type> args)
{
    std::copy(args.start(), args.end(), m_tData);
}

但是,如果我尝试使用一个const类,比如 Test<const int, 3>({1, 2, 3}),那么这个方法就行不通了。难道我必须使用模板特化来使内部数组实际上不是const,以便我可以从构造函数体中初始化它吗?
我正在使用C++20。我看到了 How do I initialize a member array with an initializer_list?,但想知道自那时以来是否有什么变化。

我认为没有任何方法可以使用 std::initializer_list 初始化数组。 - Nikos C.
@NikosC.,你可以使用包的扩展<size_t... ii>m_tData{ (*(list.begin() + ii)), ... } - Evg
@NathanOliver 这不是重复的问题。原帖明确说明:“但在这种情况下,我需要使用initializer_list”。 - Nikos C.
1
@NikosC.,我不明白为什么它不起作用。看看我的答案。唯一的事情是你不能在编译时检查initializer_list的大小。 - Evg
@Evg 确实有效!这非常棒。 - Nikos C.
1个回答

5

可能的解决方案:

template<typename Type, std::size_t Length>
class Test
{
public:
    Test(std::initializer_list<Type> args) :
        Test(args, std::make_index_sequence<Length>{})      
    {
        assert(args.size() == Length);
    }

private:
    template<std::size_t... ii>
    Test(std::initializer_list<Type> args, std::index_sequence<ii...>) :
        m_tData{(*(args.begin() + ii))...}
    {}

    Type m_tData[Length];
};

https://godbolt.org/z/d8Zg3q

是否有办法支持比模板长度小的initializer_lists?例如这样的代码Test<const int, 5>({1, 2, 3})

如果剩余元素应该使用Type{}初始化,只需要进行轻微修改:

Test(std::initializer_list<Type> args) :
    Test(args, std::make_index_sequence<Length>{})      
{
    assert(args.size() <= Length);
}

template<std::size_t... ii>
Test(std::initializer_list<Type> args, std::index_sequence<ii...>) :
    m_tData{(ii < args.size() ? *(args.begin() + ii) : Type{})...}
{}

很好的解决方案。我是否可以支持比模板长度更短的初始化列表呢?比如像这样“Test<const int, 5>({1, 2, 3})”? - code-gs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接