André Fratelli
André Fratelli

Reputation: 6068

Template function for full specialization

I have a function template declared in an header file. This function is an archiver which is supposed to support several other types (classes) implemented through the project. The idea is to have a base template declaration which each class then specialises to its own types.

// Archiver.h
template <class T> void archive(Archiver & archiver, const T & obj);

This method does not have an implementation. Now I create a class (say, Header) and I want it to be archivable. As such, it is my intent to specialise the method. Here's what I have now:

// Header.h
extern template void archive(Archiver & archiver, const Header & obj);

I declare the function as extern because I implement it in the .cpp file

// Header.cpp
template <> void archive(Archiver & archiver, const Header & obj)
{
 // Code here
}

This gives specialization after instantiation. I've tried other combinations as well:

  1. Implementing directly in the header file, as is usually recommended for templates: I get "multiple definition"
  2. Implementation in the .cpp file without a declaration on the header: I get undefined reference when calling the method from another compilation unit

So what is the correct of implementing this?

Edit:

Initially I decided to go with templates because of the inverse process, unarchiving. Basically I could write unarchive<Header>() instead of unarchive_header() which seemed more appropriate.

I believe I should also mention that I'm compiling this using Android Studio and the Gradle build system, which is why I'm using gcc and not g++. I also gave gcc the following compiler flags:

-std=gnu++11 -fexceptions -fpermissive -lstdc++

-fpermissive was an act of despair.

Upvotes: 1

Views: 524

Answers (3)

R Sahu
R Sahu

Reputation: 206607

Why use a function template?

You said:

The idea is to have a base template declaration which each class then specialises to its own types.

If a function template does not have a default implementation, it is pointless to have one at all. You can just use:

extern void archive(Archiver & archiver, const Header & obj);

when you need it.

If you must use a function template

The line

extern template void archive(Archiver & archiver, const Header & obj);

is not right. It needs to be:

template <> void archive<Header>(Archiver & archiver, const Header & obj);

The implementation needs to use the same signature.

template <> void archive<Header>(Archiver & archiver, const Header & obj)
{
}

Update, in response to OP's comment

I tried the following to simulate your situation.

socc.h:

#pragma once

struct Archiver {};

template <class T> void archive(Archiver & archiver, const T & obj);

struct Header {};

template <> void archive<Header>(Archiver & archiver, const Header & obj);

socc.cc:

#include <iostream>
#include <string>

#include "socc.h"

int main()
{
   Archiver ar;
   Header obj;
   archive(ar, obj);
}

socc-2.cc:

#include "socc.h"

template <> void archive<Header>(Archiver & archiver, const Header & obj)
{
}

Command to build:

g++ -std=c++11 -Wall    socc.cc  socc-2.cc -o socc

The program was built successfully.

Upvotes: 1

cdonat
cdonat

Reputation: 2822

In this case I think, overloading simply does the trick. You don't really need templates here.

void archive(Archiver & archiver, const Header & obj);
void archive(Archiver & archiver, const Footer & obj);
void archive(Archiver & archiver, const Whatever & obj);

Upvotes: 0

Barry
Barry

Reputation: 303087

Just don't use templates:

// Header.h
void archive(Archiver & archiver, const Header & obj);

and

// Header.cpp
void archive(Archiver & archiver, const Header & obj)
{
 // Code here
}

Much simpler that way. Simply make an unqualified call to archive() and make sure this overload is declared in the same namespace as Header and let ADL do its magic.

Upvotes: 4

Related Questions