Пожалуйста, объясните мне, почему следующий фрагмент кода соответствует и работает отлично.
Я очень смущен.
#include<iostream>
template<class A = int, class B=double>
class Base
{};
template<class B>
class Base <int, B>
{
public:
Base()
{
std::cout<<"it works!!!!!\n";
}
};
int main()
{
Base<> base; // it prints "it works!!!!!"return 0;
}
Разве это не должно попадать в обобщенную форму шаблона класса Base?
Аргумент по умолчанию применяется к специализации — и, фактически, специализация должна принимать (так сказать) аргумент (ы) базового шаблона по умолчанию. Попытка указать значение по умолчанию в специализации:
template<class A = int, class B=double>
class Base
{};
template<class B=char>
// ...
…это ошибка.
Аналогично, если мы изменим специализацию так, чтобы ее специализация была для типа Другой чем значение по умолчанию, предоставляемое базовым шаблоном:
template<class A = int, class B=double>
class Base
{};
template<class B>
class Base <char, B>
…тогда будет выбран базовый шаблон.
Итак, что происходит, так это: сначала выбираются типы для аргументов шаблона. В этом случае (при создании экземпляра тип не указан) оба типа основаны на аргументах шаблона по умолчанию, указанных в базовом шаблоне.
Затем (как отдельный шаг) он выполняет аналог разрешения перегрузки для всех шаблонов, которые соответствуют этим типам аргументов. Как обычно для разрешения перегрузки, тип, который указан явно, предпочтительнее, чем тип, который указан неявно, поэтому ваша специализация (которая указала int
явно) предпочтительнее, чем базовый шаблон (который указан int
неявно).
template<class A = int, class B=double>
class Base
{};
Здесь значения по умолчанию / инициализация для A и B были объявлены соответственно как int и double.
template<class B>
class Base <int, B>
Здесь, в определениях классов, первый аргумент является чем-то вроде постоянного значения (здесь int; зачем объявлять этот способ просто усложняющим? Лучше удалить первый аргумент шаблона), а вторым аргументом шаблона является B, значение по умолчанию которого равно double.
Base<> base;
Когда вы создаете объект класса. Хотя вы не указываете аргументы шаблона, компилятор принимает значения по умолчанию аргументов (A и B), которые являются ‘int’ и ‘double’, и код выполняется без каких-либо ошибок или предупреждений.
Посмотрите, что происходит, когда вы создаете объект как:
Base<float,char> b;
или же Base<char,char> b;
Когда ты пишешь Base<> base;
компилятор попытается выяснить, является ли Base<>
Класс возможен или нет, если это возможно, код будет работать нормально.
В этом случае это возможно из-за стандартного аргумента шаблона Base, потому что компилятор знает, если вы, если вы пишете Base<>
это должно создать объект Base<int,double>
, т.е. из-за:
template<class A = int, class B=double>
class Base
{};
Так что код работает нормально.