Почему параметры шаблона требуются при определении функций-членов шаблона класса вне класса? - PullRequest
0 голосов
/ 03 марта 2019

В следующем коде, почему я должен написать someClass<Item>::increment() вместо просто someClass::increment()?

Разве компилятор сам не должен понимать, что someClass - это класс шаблона, которыйзанимает <typename Item>?

template <typename Item>
struct someClass {
    void increment();
    Item x;
};

template <typename Item>
void someClass<Item> :: increment() {
    x++;
}

Ответы [ 3 ]

0 голосов
/ 03 марта 2019

Если компилятор сам не поймет, что someClass - это шаблонный класс, который принимает <typename Item>?

Когда компилятор увидит ::,он еще не знает, что вы на самом деле делаете .Все, что он видит, это то, что слева от этого знака.Таким образом, он видит заголовок шаблона, за которым следует имя типа (void), за которым следует имя шаблона класса, за которым следует оператор области видимости (::).Вот и все.

Шаблоны на самом деле не существуют в C ++;они являются механизмом времени компиляции для создания вещей: классов, функций и переменных в C ++ 14.Имя шаблона именует шаблон, но имя, за которым следуют его параметры шаблона, - это то, что фактически создает то, для чего предназначен шаблон.someClass называет шаблон класса;someClass<Item> называет класс , а не шаблон класса.

И после имени класса может следовать ::.

То, что вы в основном проситедля компилятора, чтобы посмотреть на заголовок шаблона, увидеть, что имя, которое вы дали параметру шаблона (s?), совпадает с именем, заданным для параметров шаблона шаблона someClass, и затем автоматически подставить его в.Это просто не так, как работает C ++.То, что вы запрашиваете, не сильно отличается от ожидания, что компилятор заполнит параметры функции только потому, что имя переменной на сайте вызова случайно совпадает с именем параметра в вызываемой функции.

Имена параметров, будь то функция или шаблон, не имеют значения в C ++.Они просто идентификаторы;они имеют значение только в рамках того, что объявляет эти имена.Имена параметров функции имеют значение только в пределах определяемой функции.И имена параметров шаблона имеют значение только в пределах рассматриваемого заголовка шаблона.

Ваш класс использует заголовок шаблона, отличный от определения вашего члена.Так что имена просто не имеют значения, что касается C ++.Совершенно верно сделать это:

template <typename Foo>
void someClass<Foo>::increment() {
    x++;
}

То, что вы хотите, это не то, как работает C ++.Да, в C ++ есть места, где полное имя шаблона может быть выведено на основании контекста, в котором он используется.Но они не основаны на простых именах параметров;они основаны на аргументах, переданных на сайте вызова.

0 голосов
/ 03 марта 2019

Разве компилятор сам не должен понимать, что someClass - это шаблонный класс, который принимает <typename Item>?

Не обязательно.Вот пример, который nm упомянул в комментарии: учтите, что someClass имеет специализацию:

// general template
template <typename Item>
struct someClass {
    void increment();
    Item x;
};

// specialization for std::vector<...> parameters
template <typename Item>
struct someClass<std::vector<Item>> {
    void increment();
    Item defaultItem;
};

Теперь определение шаблона функции increment выглядит следующим образом:

// general
template <typename Item>
void someClass<Item>::increment() {
    x++;
}

// specialization
template <typename Item>
void someClass<std::vector<Item>>::increment() {
    defaultItem++;
}

Как видите, оба определения имеют одинаковые значения template <typename Item>, но отличаются на someClass<...>.

0 голосов
/ 03 марта 2019

Поскольку someClass является классом шаблона, который зависит от параметра, методы и атрибуты также зависят от этого параметра шаблона:

template <typename Item>
void someClass<Item> :: increment() {
    x++;
}

Для каждого отдельного Item существует различное тело кодадля increment().Возможно, макет someClass зависит от Item, поэтому x++ ссылается на другое местоположение внутри this.

В этом конкретном примере Item никогда не используется напрямую, поэтому язык можетсделать это неявно.Можно утверждать, что код можно сделать немного короче.Это делается с помощью CTAD , что намного сложнее.В тех редких случаях, когда можно было бы сохранить пару строк, стоит вопрос, стоит ли усложнять язык и добавлять фактор неожиданности.По крайней мере, с CTAD есть преимущества.Многие программисты будут удивлены, обнаружив, что нечто, похожее на обычный класс, на самом деле является классом шаблона.

В C ++ уже есть много сюрпризов, поэтому можно утверждать, что еще один сюрприз не имеет большого значения.Все сводится к вопросу мнения, а не какой-то глубокой технической причине, требующей явного (и избыточного) параметра шаблона в этом примере.ТАК политика против мнений и поддерживает факты, поэтому, пожалуйста, не углубляйтесь в это.

...