Инициализация элемента по умолчанию должна ссылаться на существующий конструктор, независимо от того, используется ли он когда-либо или нет. Итак, глядя на структуру 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_ptr
и std::make_unique
:
class Bar1{
unique_ptr<Foo> foo = make_unique<Foo>(); #compiler doesn't complain
Bar1() : foo(make_unique<Foo>(0)){}
}
Это вызывает недоумение, поскольку компиляция завершается с ошибкой, как только Bar1
содержит один конструктор, где foo
не находится в списке инициализации.
Я могу подтвердить это в отношении MSVC12. Может быть, это ошибка компилятора?
Ниже приведена отдельная модель, демонстрирующая проблему:
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>
как только они указывают ссылку.
Цитата из С++ 11:
14.7.1 Неявное создание экземпляра [temp.inst]
9 Если шаблон функции или специализация шаблона функции члена используются таким образом, который включает в себя разрешение перегрузки, объявление специализации неявно создается (14.8.3).
Это поддерживает компиляторы, которые выдает ошибку: f<void>()
требует разрешения перегрузки, поэтому это создает экземпляр f<void>
. Там некоторая свобода для экземпляров шаблонов шаблонов:
14.7.1 Неявное создание экземпляра [temp.inst]
6 Если процесс разрешения перегрузки может определить правильную функцию для вызова без создания экземпляра определения шаблона класса, то не указано, действительно ли это создание.
но (вопреки тому, что я изначально написал в своем ответе), я не думаю, что это относится ко всем функциям.
Если для шаблонов функций не существует аналогичного исключения, и я не смог его найти, я думаю, что компиляторы должны диагностировать ошибку, и в настоящее время для шаблонов функций фактически не разрешено ленивое создание экземпляров.
make_unique<Foo>()
никогда не создается, потому что MSVC определил, что она никогда не будет вызываться, поэтому недопустимый вызов Foo()
даже не существует. Большое спасибо.