How to provide a explicit specialization to only one method in a C++ template class?
Asked Answered
A

2

5

I have a template class that looks something like this:

template<class T> class C
{
    void A();
    void B();

    // Other stuff
};

template<class T> void C<T>::A() { /* something */ }
template<class T> void C<T>::B() { /* something */ }

What I want is to provide an explicit specialization for only A while retaining the default for B and the "other stuff".

What I have tried so far is

class D { };
template<> void C<D>::A() { /*...*/ } // Gives a link error: multiple definition

Every other variant I've attempted fails with parse errors.


What I did:

The original problem was that the explicit specialization was in a header file so it was getting dumped into several object files and messing up the link (Why doesn't the linker notice all the instances of the symbol are the same a just shut up?)

The solution ends up being to move the explicit specialization from the header file to a code file. However to make the other users of the header file not instance the default version, I needed to place a prototype back in the header. Then to get GCC to actually generate the explicit specialization, I needed to place a dummy variable of the correct type in the code file.

Assimilative answered 26/9, 2009 at 17:20 Comment(2)
It's all in a header file that is included in several source files.Assimilative
@Magnus Hoff: that has something to do with it. A test case in 2 files fails, but works if jammed into a single file.Assimilative
M
8

Alternatively to Martin York's inline solution you could also do in your header file:

class D { };
template<> void C<D>::A(); // Don't implement here!

And supply a .cpp file with the implementation:

template<> void C<D>::A() { /* do code here */ }

So you avoid the multiple definitions by supplying a single one. This is also good to hide implementations for specific Types away from the template header file when publishing the library.

Muskogee answered 26/9, 2009 at 18:13 Comment(1)
That's exactly what I ended up doing so you get the check mark.Assimilative
M
5

Try

template<> inline void c<int>::A() { ... }
//         ^^^^^^

As you have defined it in a header file. Each source file that sees it will build an explicit version of it. This is resulting in your linking errors. So jsut declare it as inline.

Myles answered 26/9, 2009 at 17:25 Comment(6)
what does the inline do? (I thought that was part of an non-template corner of C++)Assimilative
@BCS: template and inline are orthogonal. (However, while this might hide the error, it doesn't fix it at all.)Hoisch
It does make things compile (and seem to run correctly). OTOH I forgot to point out that the function in question is virtual (and from a base class) so I'm not sure it can be inlined. So who knows what is going on.Assimilative
@Assimilative what goes on is exactly what Martin described, of course. The function is inline, so it's similar to the non-template case of "struct F { void g() { } };" which will not throw an error (g is inline) while "struct F { void g(); }; void F::g() { }" will throw a "multiple definition" error (g is not inline). Inline functions can be defined multiple times.Mcintire
@BCS: don't take the inline keyword literally. The 'act' of inlining is up-to the compiler. But a function marked inline may have multiple physical implementations across compilation units without causing the linker to complain.Myles
@sbi: It does fix the problem quite legally. BUT. I would use the solution proposed by rstevens.Myles

© 2022 - 2024 — McMap. All rights reserved.