В эпоху просвещения в 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
, является достаточной информацией, чтобы знать, что тип шаблона m
и, следовательно, тип шаблона pm
, равен string
.
Более того, следующее всегда вызовет ошибку компиляции :
MyClass s(string("blah blah blah"));
MyClass i(3);
i = s;
Это потому, что объявление конструктора копирования не templated:
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's answer
Это, насколько я могу судить, единственный ответ, чтобы вызвать законную озабоченность по поводу предлагаемой функции.
Пример:
Variable var(num); // If equivalent to Variable<int> var(num),
Variable var2(var); // Variable<int> or Variable<Variable<int>> ?
Ключевой вопрос заключается в том, выбирает ли здесь компилятор конструктор с типом или конструктор copy ?
Попробовав код, мы увидим, что выбран конструктор копирования. Расширить пример :
Variable var(num); // infering ctor
Variable var2(var); // copy ctor
Variable var3(move(var)); // move ctor
// Variable var4(Variable(num)); // compiler error
Я не уверен, как это указано в предложении и новой версии стандарта; кажется, что это определяется «руководствами по выводам», которые являются новым стандартом, которого я пока не понимаю.
Я также не уверен, почему вычет var4
является незаконным; ошибка компилятора в g ++, похоже, указывает на то, что оператор анализируется как объявление функции.