2015-10-21 214 views
1

我有一个头文件中声明的函数模板。该功能是一个归档器,应该支持通过该项目实施的其他几种类型(类)。这个想法是有一个基本的模板声明,每个类然后专门针对它自己的类型。完全专业化的模板功能

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

该方法没有实现。现在我创建一个类(例如,Header),我希望它可以存档。因此,我的意图是专门化该方法。这是我现在有:

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

我宣布的功能extern因为我在.cpp文件

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

这给specialization after instantiation实现它。我试过其他的组合,以及:

  1. 在头文件中直接实现,因为通常建议模板:我得到“多重定义”在.cpp文件
  2. 实施不会对头部的声明:当从另一个编译单元调用该方法时,我得到undefined reference

那么实现这个的正确性是什么?

编辑:

起初,我决定去,因为逆过程的模板,解除存档。基本上我可以写unarchive<Header>()而不是unarchive_header()这似乎更合适。

我相信我也应该提一下,我正在编译使用Android Studio和Gradle构建系统,这就是为什么我使用gcc而不是g ++。我也给海湾合作委员会下列编译器选项:

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

-fpermissive是一种绝望的行为。

+1

为什么不使用单独的函数? – melpomene

+0

除非你有一个非常好的理由将归档作为一个单独的函数,否则我建议用其他方法来完成:使用你想要实现的类的虚拟方法(以及可以实现的所有类的ABC /接口) 。这就是我会用的。 –

回答

5

只要不使用模板:

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

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

简单多了这种方式。只需对archive()进行非限定的调用,并确保此过载在与Header相同的名称空间中声明,并让ADL发挥它的魔力。

+0

我相信在那个时候我决定使用模板,因为反向处理,取消存档。我可以写'unarchive

()',而不是'unarchive_header()'。我认为第一种形式更方便 –

+0

@AndréFratelli为什么你认为你必须写'unarchive_header()'?只需写'unarchive()'。 – Barry

+0

因为'Header'不是唯一不可读的类,并且这个函数不会被覆盖,因为它没有得到任何参数 –

2

为什么要使用函数模板?

你说:

的想法是有一个基本模板的声明,每个类,然后专门到它自己的类型。

如果一个函数模板没有默认实现,那么根本没有意义。你可以使用:

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

当你需要它时。

如果你必须使用一个函数模板

线

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

是不对的。它需要是:

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

该实现需要使用相同的签名。

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

更新,响应OP的评论

我尝试以下,以模拟你的情况。

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) 
{ 
} 

命令编译:

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

该程序已成功构建。

+0

第二种方法在调用点提供“未定义的引用”。我仍在研究不使用模板。 –

+0

@AndréFratelli,请参阅更新。 –

+0

你可以让它与gcc一起工作吗?我试着添加'-lstdC++'编译器标志。我最初没有提及它(它看起来不相关),但我使用Gradle为Android构建。我也在研究如何用gradle –

0

在这种情况下,我认为,重载只是伎俩。这里你不需要模板。

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