使用不同对象时模板特化的多重定义

pza*_*oni 80 c++ templates

当我在不同的目标文件中使用专用模板时,链接时出现"多重定义"错误.我找到的唯一解决方案涉及使用"内联"功能,但它似乎只是一些解决方法.如何在不使用"inline"关键字的情况下解决这个问题?如果那不可能,为什么?

这是示例代码:

paulo@aeris:~/teste/cpp/redef$ cat hello.h 
#ifndef TEMPLATE_H
#define TEMPLATE_H

#include <iostream>

template <class T>
class Hello
{
public:
    void print_hello(T var);
};

template <class T>
void Hello<T>::print_hello(T var)
{
    std::cout << "Hello generic function " << var << "\n";
}

template <> //inline
void Hello<int>::print_hello(int var)
{
    std::cout << "Hello specialized function " << var << "\n";
}

#endif
Run Code Online (Sandbox Code Playgroud)
paulo@aeris:~/teste/cpp/redef$ cat other.h 
#include <iostream>

void other_func();
Run Code Online (Sandbox Code Playgroud)
paulo@aeris:~/teste/cpp/redef$ cat other.c 
#include "other.h"

#include "hello.h"

void other_func()
{
    Hello<char> hc;
    Hello<int> hi;

    hc.print_hello('a');
    hi.print_hello(1);
}
Run Code Online (Sandbox Code Playgroud)
paulo@aeris:~/teste/cpp/redef$ cat main.c 
#include "hello.h"

#include "other.h"

int main()
{
    Hello<char> hc;
    Hello<int> hi;

    hc.print_hello('a');
    hi.print_hello(1);

    other_func();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)
paulo@aeris:~/teste/cpp/redef$ cat Makefile
all:
    g++ -c other.c -o other.o -Wall -Wextra
    g++ main.c other.o -o main -Wall -Wextra
Run Code Online (Sandbox Code Playgroud)

最后:

paulo@aeris:~/teste/cpp/redef$ make
g++ -c other.c -o other.o -Wall -Wextra
g++ main.c other.o -o main -Wall -Wextra
other.o: In function `Hello<int>::print_hello(int)':
other.c:(.text+0x0): multiple definition of `Hello<int>::print_hello(int)'
/tmp/cc0dZS9l.o:main.c:(.text+0x0): first defined here
collect2: ld returned 1 exit status
make: ** [all] Erro 1
Run Code Online (Sandbox Code Playgroud)

如果我取消注释hello.h中的"inline",代码将编译并运行,但这对我来说似乎是某种"解决方法":如果专用函数很大并且多次使用该怎么办?我会得到一个大二进制文件吗?有没有其他方法可以做到这一点?如果有,怎么样?如果没有,为什么?

我试图寻找答案,但我得到的只是"使用内联"而没有任何进一步的解释.

谢谢

Stu*_*etz 109

直观地说,当你完全专门化某些东西时,它不再依赖于模板参数 - 所以除非你使内联专业化,你需要将它放在.cpp文件而不是.h中,否则你最终会违反大卫说,一个定义规则.请注意,当您对模板进行部分特化时,部分特化仍然依赖于一个或多个模板参数,因此它们仍然位于.h文件中.

  • 在C++的上下文中"直观地"使用是温和的,相当大胆...... (7认同)
  • @JustinLiang:标题包含在两个单独的.c文件中 - 这与您将其内容(包括完整专业化)直接写入相关位置所包含的文件具有相同的效果.一个定义规则(参见http://en.wikipedia.org/wiki/One_Definition_Rule)说(除其他外):"在整个程序中,对象或非内联函数不能有多个定义".在这种情况下,函数模板的完全特化实质上就像普通函数一样,所以除非它是内联的,否则它不能有多个定义. (3认同)

Dav*_*eas 43

关键字inline更多的是告诉编译器符号将出现在多个目标文件中而不违反单一定义规则而不是实际内联,编译器可以决定做或不做.

您看到的问题是,如果没有内联,该函数将在包含标题的所有翻译单元中编译,违反ODR.添加inline有正确的方法.否则,您可以转发声明专业化并将其提供在单个翻译单元中,就像使用任何其他功能一样.


Edw*_*nge 19

您已在头文件(void Hello<T>::print_hello(T var))中明确实例化了一个模板.这将创建多个定义.您可以通过两种方式解决它:

1)使您的实例化内联.

2)在头中声明实例化,然后在cpp中实现它.

  • 这在这里无效.模板特化需要与原始模板位于同一名称空间中. (4认同)