模板代码中的统一初始化

时间:2016-03-22 10:33:42

标签: c++ templates c++11 g++4.8 uniform-initialization

据我所知,uniform initialization是初始化对象的首选语法。 Herb Sutter writes

  

首先,它被称为“统一初始化”,因为它对所有类型都是相同的 - 包括聚合结构和数组以及std :: containers ......

以及this question州已接受的答案

  

除非你有充分的理由不这样做,否则首选{}初始化替代品。

但是,请考虑以下代码:

#define BRACES                                                                                                                                                                                           

template<typename V>
class foo {   
public:
    template<typename W>
    explicit foo(const W &w) : 
#ifdef BRACES
        m_v{w}
#else // #ifdef BRACES
        m_v(w)
#endif // #ifdef BRACES
    {}  

private:
    V m_v;
};  

struct bar{};  

int main() 
{   
    bar b;

    foo<bar>{b};
#ifdef BRACES
    bar c{b};
#else // #ifdef BRACES
    bar c(b);
#endif // #ifdef BRACES                                                                                                                                                                                  
}   

如果取消注释#define BRACES,则此代码无法在行上使用error: too many initializers for ‘bar’构建(g ++ 4.8.5)

    m_v{w}
foo的构造函数中的

。这是有意义的,因为更直接的调用

 bar c{b};
main中的

同样失败,它们基本相同(虽然模板代码不知道)。

相反,评论#define BRACES会导致所有内容构建。这是否是在这种类型的模板代码中避免这种形式的初始化的指示?

修改

@ melak47指出这个问题没有出现在g ++ 5.1中,并且给了convincing proof。它显然在4.8.5和5.1之间消失了。

2 个答案:

答案 0 :(得分:2)

当您尝试从相同类型的某些内容初始化聚合时,列表初始化不太有效。

这是CWG 1467,其解决方案(除其他事项外)为[dcl.init.list]/3中的巨型列表引入了另一个子弹以使其工作:

  

定义了T类型的对象或引用的列表初始化   如下:

     
      
  • 如果T是类类型且初始值设定项列表包含 cv U类型的单个元素,则其中UT或一个派生自T的类,   object从该元素初始化(通过复制初始化)   copy-list-initialization,或者直接初始化   直接一览初始化)。
  •   

答案 1 :(得分:-1)

当解析重载的构造函数时,在考虑其他重载的构造函数之前,braced初始化将使用std :: initializer_list参数匹配构造函数。所以

bar c{b};

将与采用std :: initializer_list的构造函数匹配,而不是生成的复制构造函数。

在第7项中讨论了这一点:在创建Scott Meyers的对象时,区分()和{} C ++。

此外,Wikipedia - C++11 Uniform initialization