В просвещенную эпоху 2016 года, когда у нас за плечами два новых стандарта, поскольку этот вопрос был задан, и новый не за горами, важно знать, что компиляторы, поддерживающие стандарт C ++ 17, будут компилировать ваш код как есть. .
Вывод шаблона-аргумента для шаблонов классов в C ++ 17
Здесь (любезно предоставлено редакцией принятого ответа Олжасом Жумабеком) документ с подробным описанием соответствующих изменений в стандарте.
Решение проблем, связанных с другими ответами
Текущий самый популярный ответ
Этот ответ указывает на то, что «конструктор копирования и operator=
» не знает правильных специализаций шаблона.
Это чушь, потому что стандартные конструкторы-копии operator=
существуют только для известного типа шаблона:
template <typename T>
class MyClass {
MyClass(const MyClass&) =default;
... etc...
};
// usage example modified from the answer
MyClass m(string("blah blah blah"));
MyClass *pm; // WHAT IS THIS?
*pm = m;
Здесь, как я отмечал в комментариях, нет причин для того, MyClass *pm
чтобы быть законным объявлением с новой формой вывода или без нее : MyClass
это не тип (это шаблон), поэтому нет смысла объявлять указатель на тип MyClass
. Вот один из возможных способов исправить этот пример:
MyClass m(string("blah blah blah"));
decltype(m) *pm; // uses type inference!
*pm = m;
Здесь pm
он уже имеет правильный тип, поэтому вывод тривиален. Более того, невозможно случайно смешать типы при вызове конструктора копирования:
MyClass m(string("blah blah blah"));
auto pm = &(MyClass(m));
Здесь pm
будет указатель на копию m
. Здесь MyClass
создается копия, m
которая имеет тип MyClass<string>
(а не несуществующий тип MyClass
). Таким образом, в точке , где pm
выводится «S типа, там есть достаточно информации , чтобы знать , что шаблонный тип m
, и , следовательно , шаблон-типа pm
, являетсяstring
.
Более того, следующее всегда вызывает ошибку компиляции :
MyClass s(string("blah blah blah"));
MyClass i(3);
i = s;
Это потому, что объявление конструктора копирования не является шаблоном:
MyClass(const MyClass&);
Здесь шаблон типа копирования-конструктор аргумент соответствует шаблону типа класса в целом; то есть, когда MyClass<string>
создается экземпляр, MyClass<string>::MyClass(const MyClass<string>&);
создается с ним, а когда MyClass<int>
создается экземпляр, MyClass<int>::MyClass(const MyClass<int>&);
создается экземпляр. Если это не указано явно или не объявлен шаблонный конструктор, компилятор не имеет причин для создания экземпляраMyClass<int>::MyClass(const MyClass<string>&);
, что, очевидно, было бы неуместным.
Ответ Кэтэлина Питиша
Пити приводит пример вывода, Variable<int>
а Variable<double>
затем заявляет:
У меня в коде указано одно и то же имя типа (Variable) для двух разных типов (Variable и Variable). С моей субъективной точки зрения, это очень сильно влияет на читабельность кода.
Как отмечалось в предыдущем примере, Variable
само по себе не является именем типа, хотя новая функция делает его синтаксически похожим на имя типа.
Затем Пити спрашивает, что произойдет, если не будет задан конструктор, который позволил бы сделать соответствующий вывод. Ответ состоит в том, что логический вывод не разрешен, потому что вывод запускается вызовом конструктора . Без вызова конструктора нет вывода .
Это похоже на вопрос о том, какая версия foo
выведена здесь:
template <typename T> foo();
foo();
Ответ заключается в том, что этот код является незаконным по указанной причине.
Ответ MSalter
Насколько я могу судить, это единственный ответ, который вызывает законное беспокойство по поводу предлагаемой функции.
Пример такой:
Variable var(num); // If equivalent to Variable<int> var(num),
Variable var2(var); // Variable<int> or Variable<Variable<int>> ?
Ключевой вопрос заключается в том, выбирает ли компилятор здесь конструктор с выводом типа или конструктор копирования ?
Пробуя код, мы видим, что выбран конструктор копирования. Чтобы развернуть пример :
Variable var(num); // infering ctor
Variable var2(var); // copy ctor
Variable var3(move(var)); // move ctor
// Variable var4(Variable(num)); // compiler error
Я не уверен, как это указывается в предложении и новой версии стандарта; Похоже, что это определяется «руководящими принципами дедукции», которые представляют собой новый стандарт, который я еще не понимаю.
Я также не уверен, почему var4
удержание незаконно; ошибка компилятора из g ++, похоже, указывает на то, что оператор анализируется как объявление функции.