Почему иногда используется базовый тип в качестве компиляции базового класса? - PullRequest
4 голосов
/ 21 февраля 2020

Компилируется (протестировано с G CC 9 и Clang 9):

template<typename U>
struct inherit : U { };

int test(inherit<int> arg);

Но это не так:

int test(inherit<int> arg) { }

Почему компилируется первый?

Ответы [ 2 ]

6 голосов
/ 21 февраля 2020

int test(inherit<int> arg); это просто декларация. Таким образом, нам пока не нужно знать о inherit<int>. Из-за этого компилятор позволит ему go.

С int test(inherit<int> arg) { } у вас теперь есть определение, и теперь нам нужно знать о inherit<int>, чтобы arg можно было уничтожить при выходе из функции. В этот момент создается экземпляр шаблона, и вы получаете ошибку, потому что он недействителен.

Другая причина игнорировать объявление состоит в том, что inherit может позже стать специализированным для int, и что специализация может быть допустимый класс, поскольку у вас может быть что-то вроде

template<>
struct inherit<int> { };

Если вы добавите это значение между int test(inherit<int> arg); и int test(inherit<int> arg) { }, тогда код будет компилироваться, поскольку inherit<int> теперь является допустимым типом.

1 голос
/ 21 февраля 2020

Я надеюсь, что кто-то еще объяснит почему. Я буду использовать феноменологический подход здесь;).

Ваша первая версия также не будет скомпилирована, когда вы на самом деле создадите inherit<int>:

int main() {
    test( inherit<int>{} );
}

Ошибка:

prog.cc: In instantiation of 'struct inherit<int>':
prog.cc:9:24:   required from here
prog.cc:4:8: error: base type 'int' fails to be a struct or class type
    4 | struct inherit : U { };
      |        ^~~~~~~

Я мог бы просто попытаться создать объект inherit<int> (без вызова test), чтобы получить похожую ошибку.

С другой стороны, это всего лишь объявление: int test(inherit<int> arg); перед тем, как на самом деле предоставить определение может быть специализацией для inherit, что позволяет нам также предоставить действительное определение для test:

template<typename U>
struct inherit : U { };

// looks broken
int test(inherit<int> arg);
// but that this point we dont really know yet what `inherit<int>` really is

// whoops inherit<int> is something different now   
template <> struct inherit<int> {};

// ... and now this is completely fine
int test(inherit<int> arg) {}

int main() {
    test( inherit<int>{} );
}
...