为什么std :: make_unique在默认成员初始化中不需要参数,如果从未调用它?

时间:2014-09-21 13:21:05

标签: c++ c++11 initialization default unique-ptr

默认成员初始化需要引用现有构造函数,无论它是否曾被使用过。所以,查看没有默认构造函数的结构Foo

struct Foo{
    Foo(int x) : x_(x){}
    int x_;
};

很明显,以下内容不起作用,并导致编译错误:

class Bar0{
    Foo foo = Foo(); #constructor Foo() doesn't exist
    Bar0() : foo(0){}
}

但是,std::unique_ptrstd::make_unique

是一个不同的故事
class Bar1{
    unique_ptr<Foo> foo = make_unique<Foo>(); #compiler doesn't complain
    Bar1() : foo(make_unique<Foo>(0)){}
}

这很令人费解,因为只要Bar1包含一个foo不在初始化列表中的构造函数,编译就会失败。

我可以确认MSVC12的确如此。它可能是编译器错误吗?

1 个答案:

答案 0 :(得分:4)

这是一个展示问题的独立样本:

template <typename T>
int f() {
  return T();
}

struct S {
  int i = f<void>();
  S() : i(0) { }
};

在您的示例中,f被命名为make_unique,并且它不会返回int,但这并没有从根本上改变任何内容。

是的,Visual Studio的编译器接受了这一点,而其他编译器也没有。 Visual Studio延迟实例化它不需要的模板。其他编译器一发现引用就会实例化f<void>

引用C ++ 11:

  

14.7.1隐式实例化[temp.inst]

     

9如果以涉及重载解析的方式使用函数模板或成员函数模板特化,则隐式实例化特化的声明(14.8.3)。

这支持发出错误的编译器:f<void>()需要重载解析,因此实例化f<void>。类模板实例有一些余地:

  

14.7.1隐式实例化[temp.inst]

     

6如果重载解析过程可以在不实例化类模板定义的情况下确定要调用的正确函数,则不确定是否实际发生了该实例化。

但是(与我最初在答案中写的相反)我认为它不适用于整个职能机构。

除非功能模板有类似的例外,并且我还没有找到,我认为编译器需要诊断错误,而且实际上当前不允许延迟实例化功能模板。