1. ホーム
  2. c++

[解決済み] 異なるオブジェクトを使用した場合のテンプレート特殊化の多重定義

2022-09-28 01:16:04

質問

特殊なテンプレートを異なるオブジェクトファイルで使用すると、リンク時に "多重定義" というエラーが発生します。唯一の解決策は、"inline" 関数を使用することですが、それは何か回避策のように思えます。どうすれば、"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


paulo@aeris:~/teste/cpp/redef$ cat other.h 
#include <iostream>

void other_func();


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


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;
}


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


最後に

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

hello.h 内の "inline" をアンコメントすると、コードはコンパイルされて実行されますが、それはある種の "workaround" にしか思えません。特殊化された関数が大きく、何度も使用される場合はどうでしょうか。大きなバイナリを取得するのでしょうか。他に方法はないのでしょうか?もしあるならば、どのように?ない場合は、なぜですか?

私は答えを探そうとしましたが、私が得たのは、さらなる説明なしに"use inline"だけでした。

ありがとうございます。

どのように解決するのですか?

直感的には、何かを完全に特殊化すると、テンプレート パラメータに依存しなくなります。したがって、特殊化をインラインにしない限り、それを .h の代わりに .cpp ファイルに置く必要があり、さもなければ David が言うように 1 つの定義ルールに違反することになります。テンプレートを部分的に特殊化するとき、部分的な特殊化はまだ1つまたは複数のテンプレート パラメータに依存するので、まだ .h ファイルに置くことに注意してください。