2

I have an explicitly instantiated template class with specializations:

// 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

The above files are compiled into a static library with 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

I would expect that a1.o contains A<1>::foo(), and a2.o contains A<2>::foo(), but not the other way around, since there is only one instantiation in each of the .cc files.

It turns out, however, that both object files contain both functions. VS2015RC also gives linker warnings:

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

Why?

Also, if I comment out the specialization for N=2, with g++ it still compiles silently, even though the explicitly instantiated N=2 case has an unresolved function... (VS2015RC warns that "no suitable definition provided for explicit template instantiation request", as expected).


Clarification - according to the standard (14.7.3.6):

If a [..] member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs[.]

This passage (implicitly) states, that a use of the specialization is needed for it to be instantiated.

My problem is that A<2>::foo() is implicitly instantiated in a1.o, even though there was no use of this specification in that translation unit.

vukung
  • 1,824
  • 10
  • 23

2 Answers2

3

Your specialization are not inline. so you have one definition by translation unit including a.in.

Add inline keyword:

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

or move definition in cpp file:

// 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
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Moving the definition to the cpp file works, but the main question was why are the specializations compiled in both object files? Even if not inline, a template function should be compiled only if used or if explicitly instantiated, but in a1.o there is no reference to A<2>, and vice versa. – vukung Jul 10 '15 at 15:01
  • 1
    @vukung: template are `inline`, but full specialization are non longer template. – Jarod42 Jul 10 '15 at 15:04
1

I would say that your code

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

it's an esplicit definition of the member function and as such cannot be done twice. So make sure is inside one translation unit only.

14.7.3 Explicit specialization

5 A member of an explicitly specialized class is not implicitly instantiated from the member declaration of the class template; instead, the member of the class template specialization shall itself be explicitly defined if its definition is required.

Community
  • 1
  • 1
marom
  • 5,064
  • 10
  • 14
  • That looks like it... still, the standard says "if its definition is required" - but it isn't, is it? – vukung Jul 10 '15 at 15:08
  • Definition is required since definition of template A declares foo() without defining it. – marom Jul 10 '15 at 15:23
  • The definition of A<1>::foo() is required in a1.o, since it instantiates A<1>. But the definition of A<2>::foo() is not required there - you can comment it out, and it will still compile a1.o without any errors. So, once again, the question is why is A<2>::foo() compiled into a1.o, even though it is not required? – vukung Jul 10 '15 at 15:38