Несколько экземпляров специализированных шаблонов
У меня есть явно экземпляр класса шаблона со специализациями:
// 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 Член явно специализированного класса неявно создается из объявления члена шаблона класса; вместо этого член специализации шаблона класса должен быть явно определен, если требуется его определение.