为什么 vector 在其构造函数中采用initializer_list而不是使用可变参数模板?

Why does vector take an initializer_list in its constructor instead of using a variadic template?

提问人:TwistedBlizzard 提问时间:7/8/2023 最后编辑:TwistedBlizzard 更新时间:7/9/2023 访问量:105

问:

在此代码中

vector<std::string> vec = { "long string", "exterminate" };

创建一个 of,并将 中的每个元素复制到 中。这是低效的,并且无法使用仅移动类型初始化向量。为什么构造函数不能完美地转发参数? 如果这是真的,你可以这样做:initializer_liststd::stringvec

vector<unique_ptr<int>> vec = {
    make_unique<int>(5), make_unique<int>(55), make_unique<int>(-4)
};

取而代之的是:

vector<unique_ptr<int>> vec;
vec.push_back(make_unique<int>(5));
vec.push_back(make_unique<int>(55));
vec.push_back(make_unique<int>(-4));

此外,如果关心复制其构造函数中的元素,为什么允许使用 ?vectorpush_back

C++ variadic-templates 初始值设定项列表

评论

0赞 273K 7/8/2023
push_back在所示的可能构造函数中是无效的。
0赞 273K 7/8/2023
请参阅相关问题 stackoverflow.com/questions/9618268/...
3赞 康桓瑋 7/8/2023
然后更改 的含义。vector v(0, 1)
0赞 TwistedBlizzard 7/8/2023
@康桓瑋这很有道理。我想如果您遇到这些歧义,禁用该构造函数会太令人困惑了。
0赞 Pepijn Kramer 7/8/2023
您始终可以创建一个免费函数,以帮助您以这种方式创建唯一的指针。

答:

0赞 Roman Leshchuk 7/9/2023 #1

不幸的是,使用构造函数不可能获得您想要获得的行为。它不能使用可变模板,因为是单一类型的容器,所以可变可变参数模板构造函数不是类型安全的。如果确实要构造具有不可复制元素的容器,请考虑使用以下函数:std::vectorstd::vectorstd::vector

template <typename T, size_t S>
std::vector<T> construct(std::array<T, S>&& elems)
{
    std::vector<T> result{};
    result.reserve(elems.size());
    for (T& elem : elems)
    {
        result.push_back(std::move(elem));
    }
    return result;
}

您需要以这种方式传递给它:std::array

construct(std::array{ make_unique<int>(7), make_unique<int>(67) });

您可以简单地使用不可复制的类型,因为它们不是 ,而它们在 .出于这个原因,上面的函数用于此目的,因为这个容器允许通过非常量引用或迭代器访问其元素,这允许非常量访问。push_backconstconststd::initializer_liststd::array

评论

0赞 TwistedBlizzard 7/9/2023
您可以使用类型特征(如 std::combined 和 std::is_convertible 来使构造函数类型安全,不是吗?
0赞 Roman Leshchuk 7/9/2023
是的,但是可变参数模板是为将不同类型的类型传递给构造函数而制作的。因此,该标准不会在单一类型的容器中使用它们。 是专门为此目的制作的,但是这个容器有一些缺点,例如,它不能移动。所以在这种特定情况下应该使用。std::initializer_liststd::array