c++ - 初始化时统一初始化还是直接初始化?

标签 c++ c++11 initialization

假设我有一个模板,用于存储 T 类型的对象.我想传递构造函数参数以初始化数据成员。我应该使用统一初始化还是带非花括号的直接初始化?:

template<typename T>
struct X
{
    template<typename... Args>
    X(Args&&... args)
             : t(std::forward<Args>(args)...) // ?
    /* or */ : t{std::forward<Args>(args)...} // ?
private:
    T t;
};

如果我要存储的对象是一个 std::vector我选择花括号样式(统一初始化)然后我传递的参数将被转发到 vector::vector(std::initializer_list<T>)构造函数,这可能是也可能不是我想要的。

另一方面,如果我使用非大括号样式,我将失去通过 std::initializer_list 向 vector 添加元素的能力。构造函数。

当我不知道我正在存储的对象和将传入的参数时,我应该使用什么形式的初始化?

最佳答案

需要明确的是,对于具有多个构造函数的类型,包括采用 std::initializer_list 的类型,会出现歧义。 , 另一个参数(用大括号初始化时)可能被解释为 std::initializer_list由编译器。例如,std::vector<int> 就是这种情况。 :

template<typename T>
struct X1
{
    template<typename... Args>
    X1(Args&&... args)
             : t(std::forward<Args>(args)...) {}

    T t;
};

template<typename T>
struct X2
{
    template<typename... Args>
    X2(Args&&... args)
     : t{std::forward<Args>(args)...} {}

    T t;
};

int main() {
    auto x1 = X1<std::vector<int>> { 42, 2 };
    auto x2 = X2<std::vector<int>> { 42, 2 };
    
    std::cout << "size of X1.t : " << x1.t.size()
              << "\nsize of X2.t : " << x2.t.size();
}

(请注意,唯一的区别是 X2 成员初始化列表中的大括号而不是 X1 成员初始化列表中的圆括号)

Output :

size of X1.t : 42

size of X2.t : 2

Demo


标准库作者在编写诸如 std::make_unique 等实用程序模板时遇到了这个实际问题, std::make_sharedstd::optional<> (对于任何类型都应该完美转发):首选哪种初始化形式?这取决于客户端代码。

没有好的答案,他们通常会加上括号(最好记录选择,以便调用者知道会发生什么)。惯用的现代 c++11 更喜欢在任何地方进行大括号初始化(它避免缩小转换,避免 c++ 最令人烦恼的解析等。)


消除歧义的潜在解决方法是使用命名标签,这篇来自 Andrzej's C++ blog 的精彩文章对此进行了广泛讨论。 :

namespace std{
  constexpr struct with_size_t{} with_size{};
  constexpr struct with_value_t{} with_value{};
  constexpr struct with_capacity_t{} with_capacity{};
}

// These contructors do not exist.
std::vector<int> v1(std::with_size, 10, std::with_value, 6);
std::vector<int> v2{std::with_size, 10, std::with_value, 6};

这是冗长的,仅当您可以修改不明确的类型时才适用(例如,公开采用 std::initializer_list 的构造函数的类型和其他参数列表可能转换为 std::initializer list 的构造函数)

关于c++ - 初始化时统一初始化还是直接初始化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27894601/

相关文章:

java - 数组变量可能未初始化错误

c++ - c++11 中类作用域的数组初始化

c++ - 递归 std::stringstream 和 c_str

c++ - 未初始化的值是由堆栈分配创建的

c++ - 使用 lambdas 编译简单的 C++0x 程序时遇到问题

c++ - 为什么 std::result_of 不适用于 lambda?

c++ - 如何从 switch 语句中排除浮点值?

c++ - 使用 openssl 及其未阻塞的 bio,ssl_read 返回 SSL_ERROR_SYSCALL 和 SSL_ERROR_WANT_READ

c++ - 右值引用匹配(完美转发示例)

c++ - 在 C++ 中初始化为自身的对象