explicit specialization of class method - symbol already defined
Asked Answered
C

2

7

The One Definition Rule states that a program should contain one definition of every non-inline function. For members of template classes, this not entirely clear to me:

 ///////////
 // Tfoo.h
 template<typename T> class A { 
     void foo(){} 
 };

 ///////////
 // intfoo.h
 #include <Tfoo.h>
 template<> class Foo<int> { 
     void foo(); // declaration only
 }; 
 /*inline*/ void Foo<int>::foo(){} // definition

 ///////////
 // X.cpp
 #include <intfoo.h>

 ///////////
 // Y.cpp
 #include <intfoo.h>

In this case, both clientX.obj and clientY.obj have a definition of Foo<int>::foo. The linker complains that this symbol is defined more than once:

Y.obj : error LNK2005: "private: void __thiscall Foo<int>::foo(void)" 
(?foo@?$Foo@H@@AAEXXZ) already defined in X.obj

When I prepend inline to the definition of Foo<int>::foo(), all goes well and the linker is happy. Also when I define them the method in a separate compilation unit (e.g. intfoo.cpp).

(Note: this solution was suggested in https://mcmap.net/q/1479169/-how-to-provide-a-explicit-specialization-to-only-one-method-in-a-c-template-class)

Possibly a misconception, but aren't member functions of template classes always 'inline'? What is the rule here?

Cassady answered 23/4, 2013 at 8:25 Comment(1)
What about this?Hoof
C
11

A member function of an explicit specialization of a class template is just like a member function of a non-template class. After all, an explicit specialization is a concrete class that does not depend on any template parameter.

If you put its definition in a header file that is included by several translation units, the compiler will produce object code for that function while processing each of those translation units.

Eventually, the linker will complain about multiply defined symbols. The inline keyword prevents this behavior, just like it does for regular non-template functions or regular member functions of non-template classes.

Comorin answered 23/4, 2013 at 8:30 Comment(1)
"an explicit specialization is a concrete class": that's what I was looking for. Thanks.Cassady
R
2

You can move the definition of the explicit specialization

void Foo<int>::foo() {}

into a .cpp file. Leave a declaration in .h:

template<>
void Foo<int>::foo();
Reactor answered 12/10, 2013 at 19:15 Comment(2)
... risking that you forget to build + link the implementation.Cassady
@Cassady I like this one better and with something like a cmake build script this is but a problem :-)Adactylous

© 2022 - 2024 — McMap. All rights reserved.