У освічений вік 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;
Це відбувається тому, що декларація конструктора копіювання не шаблонована:
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>&);
, що, очевидно, було б недоречно.
Відповідь Cătălin Pitiș
Pitiș наводить приклад виведення, Variable<int>
а Variable<double>
потім констатує:
У мене в коді однакове ім’я типу (Змінна) для двох різних типів (Змінна та Змінна). З моєї суб'єктивної точки зору, це сильно впливає на читабельність коду.
Як зазначалося в попередньому прикладі, Variable
сама по собі не є назвою типу, хоча нова функція робить це схожим на одну синтаксичну.
Потім Piti asks запитує, що трапиться, якщо не буде надано жодного конструктора, який би дозволяв відповідне висновок. Відповідь полягає в тому, що не дозволяється робити висновок, оскільки висновок ініціюється викликом конструктора . Без конструктор-виклику немає висновку .
Це схоже на запитання про те, яка версія 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 ++, схоже, вказує на те, що оператор аналізується як оголошення функції.