Специализация функции: что такое декларация? - PullRequest
0 голосов
/ 25 марта 2012

Дано:

template<class T>
struct test {

    void foo(int b);

    void testFunc( int a )
    {
    }

};

void test::foo(int b)
{

}


template<>
void test<float>::testFunc( int a )
{

}

void someFunction()
{
}

Мы знаем, что "test::foo" имеет объявление в тестовом классе и определение вне определения класса.
Мы также знаем, что "someFunction"имеет объявление, которое также является его определением.
Аналогичным образом "test::testFunc" (неспециализированное), имеет объявление, которое также является его определением.
Является ли функция специализации "test<float>::testFunc", называемаяобъявлено с объявлением «testFunc» внутри класса «test» и определено отдельно, или это объявление также является определением?

Ответы [ 2 ]

3 голосов
/ 25 марта 2012

Явная специализация в вашем примере - это объявление, которое также является определением. Вы также можете объявить это отдельно:

template<>
void test<float>::testFunc( int a );

и если функция использовалась, компоновщик ожидал, что она будет где-то определена.

Объявление внутри класса - это объявление и определение шаблона функции-члена.

Кстати, foo должно быть определено так:

template <class T>
void test<T>::foo(int b)
{

}
1 голос
/ 25 марта 2012

Я хотел бы добавить к полезному ответу, предоставленному @Vaughn.

В определении шаблона test у вас есть неопределяемое объявление функции-члена, а также определение функции-члена определения.Но это определение и объявление функции связано с окружающим шаблоном test<T>, а не с классом test<float>, который в итоге будет создан из него!

Если вы неявно создаете экземпляр test<float> из этого шаблона, например, с помощью :: -оператора (области действия) или создавая определение переменной этого типа и т. Д., То декларации , но необязательно определения всех членов также неявно созданы.Все они связаны с test<float>.

и членами * Так что, когда вы пишете явную специализацию для test<float>::testFunc, потому что вы использовали ::, чтобы заглянуть в класс test<float>, этот класссоздается неявно и вместе с ним все объявления его членов.

Определение из test<float>::testFunc создается только тогда, когда это требуется (например, когда вы его вызываете).

Явная специализация, которую вы объявили тогда, повторно объявляет функцию-член, которая ранее была неявно реализована, и дает определение, что это , связанный с test<float>.Это реальная функция, и ее нельзя безопасно определить в заголовке, если она не помечена inline - в противном случае вы рискуете «определить более одного раза», если включите в его заголовок несколько таймеров.

Суммируя, какие декларации и определения существуют для testFunc и откуда они берутся:

  • По определению вашего шаблона:

    • test<T>::testFunc(int);
    • test<T>::testFunc(int) { }
  • Генерируется специализация компилятором из test<T>::testFunc(int);

    • test<float>::testFunc(int);
  • Явная специализация вами test<T>::testFunc(int);

    • test<float>::testFunc(int);
    • test<float>::testFunc(int) { }

В частности, не существует сгенерированного определения test<float>::testFunc.Если бы это было так, то ваш код был бы некорректно сформирован, без необходимости диагностики, потому что сгенерированное определение могло бы помешать вашей явной специализации, которая предоставила определение для той же функции.Но такая вещь может произойти только в том случае, если вы вызываете ее создание до явной специализации.Поэтому, если вы перенесете явное определение специализации в файл .cpp (если вы не хотите, чтобы оно было inline), поместите явное определение специализации , как показано в @Vaughn, в заголовок.

...