Несколько экземпляров специализированных шаблонов

У меня есть явно экземпляр класса шаблона со специализациями:

// a.hh
#pragma once

template<int N>
struct A {
  int foo();
};

// a.in
#include "a.hh"

template<>
int A<1>::foo() { return 1; } // specialization for N=1

template<>
int A<2>::foo() { return 2; } // specialization for N=2

// a1.cc
#include "a.in"

template struct A<1>; // explicit instantiation for N=1

// a2.cc
#include "a.in"

template struct A<2>; // explicit instantiation for N=2

Вышеуказанные файлы скомпилированы в статическую библиотеку с g++ 4.9.2:

g++ -Wall -c -o a1.o a1.cc
g++ -Wall -c -o a2.o a2.cc
ar rcs libtest.a a1.o a2.o

Я ожидал бы, что a1.o содержит A<1>::foo(), а a2.o содержит A<2>::foo(), но не наоборот, так как в каждом из них есть только один экземпляр файлы.cc.

Оказывается, однако, что оба объектных файла содержат обе функции. VS2015RC также выдает предупреждения компоновщика:

a1.obj : warning LNK4006: "public: int __thiscall A<1>::foo(void)" already defined in a2.obj; second definition ignored
a1.obj : warning LNK4006: "public: int __thiscall A<2>::foo(void)" already defined in a2.obj; second definition ignored

Зачем?

Кроме того, если я закомментирую специализацию для N=2, с g ++ она все равно будет скомпилирована без вывода сообщений, даже если в явно созданном случае N = 2 есть нерешенная функция... (VS2015RC предупреждает, что "для запроса явного создания экземпляра шаблона нет подходящего определения ", как и ожидалось).


Пояснение - согласно стандарту (14.7.3.6):

Если [..] член шаблона класса явно специализирован, то эта специализация должна быть объявлена ​​перед первым использованием этой специализации, которая вызовет неявную реализацию в каждой единице перевода, в которой такое использование происходит [.]

В этом отрывке (неявно) говорится, что для его создания необходимо использование специализации.

Моя проблема в том, что A<2>:: foo () неявно создается в a1.o, даже если в этой единице перевода не использовалась эта спецификация.

2 ответа

Ваша специализация не inline, Таким образом, у вас есть одно определение для единицы перевода, включая a.in.

добавлять inline ключевое слово:

template<>
inline int A<1>::foo() { return 1; } // specialization for N=1

или переместить определение в файл cpp:

// a1.cc
#include "a.hh"

template<>
int A<1>::foo() { return 1; } // specialization for N=1

template struct A<1>; // explicit instantiation for N=1

Я бы сказал, что твой код

template<>
int A<1>::foo() { return 1; } // specialization for N=1

это конкретное определение функции-члена, и поэтому ее нельзя сделать дважды. Поэтому убедитесь, что находится внутри одной единицы перевода.

14.7.3 Явная специализация

5 Член явно специализированного класса неявно создается из объявления члена шаблона класса; вместо этого член специализации шаблона класса должен быть явно определен, если требуется его определение.

Другие вопросы по тегам