Почему std :: make_unique не требует аргумента при инициализации члена по умолчанию, если он никогда не вызывается?

0

Инициализация элемента по умолчанию должна ссылаться на существующий конструктор, независимо от того, используется ли он когда-либо или нет. Итак, глядя на структуру 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. Может быть, это ошибка компилятора?

  • 0
  • 0
    Ваша опечатка "make_unqiue" плюс тот факт, что в результате тщательного поиска по ИСО / МЭК 14882-2011 не упоминается стандартная библиотечная функция с именем "make_unique", указывает на то, что это не тот код, с которым у вас возникают проблемы, но некоторые случайные фрагменты кода, которые вы извлекли из воздуха. Если вы хотите задать вопрос и сослаться на какой-либо код, пожалуйста, опубликуйте фактический код, с которым у вас возникли проблемы. Спасибо.
Показать ещё 1 комментарий
Теги:
c++11
initialization
default
unique-ptr

1 ответ

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> как только они указывают ссылку.

Цитата из С++ 11:

14.7.1 Неявное создание экземпляра [temp.inst]

9 Если шаблон функции или специализация шаблона функции члена используются таким образом, который включает в себя разрешение перегрузки, объявление специализации неявно создается (14.8.3).

Это поддерживает компиляторы, которые выдает ошибку: f<void>() требует разрешения перегрузки, поэтому это создает экземпляр f<void>. Там некоторая свобода для экземпляров шаблонов шаблонов:

14.7.1 Неявное создание экземпляра [temp.inst]

6 Если процесс разрешения перегрузки может определить правильную функцию для вызова без создания экземпляра определения шаблона класса, то не указано, действительно ли это создание.

но (вопреки тому, что я изначально написал в своем ответе), я не думаю, что это относится ко всем функциям.

Если для шаблонов функций не существует аналогичного исключения, и я не смог его найти, я думаю, что компиляторы должны диагностировать ошибку, и в настоящее время для шаблонов функций фактически не разрешено ленивое создание экземпляров.

  • 0
    Ах я вижу. Функция шаблона make_unique<Foo>() никогда не создается, потому что MSVC определил, что она никогда не будет вызываться, поэтому недопустимый вызов Foo() даже не существует. Большое спасибо.
  • 0
    @iFreilicht Перечитывая, я думаю, что был совершенно неправ в этом ответе. Он говорит «определение шаблона класса», ссылаясь на еще не созданный экземпляр параметра и возвращаемые типы в перегрузках функций, а не на сами функции.
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню