2016-12-30 9 views
22

私は、基本クラスのテンプレートパラメータとしてテンプレート関数を渡すと、リンカはそれが機能をリンクすることはできませんと文句を言います:中エラーメッセージ「テンプレートパラメータとして渡されたテンプレート関数に未定義の参照」

#include <stdio.h> 

template<int I> inline int identity() {return I;} 
//template<> inline int identity<10>() {return 20;} 

template<int (*fn)()> 
class Base { 
public: 
    int f() { 
     return fn(); 
    } 
}; 

template<int Val> 
class Derived : public Base<identity<10> > { 
public: 
    int f2() { 
     return f(); 
    } 
}; 

int main(int argc, char **argv) { 
    Derived<10> o; 
    printf("result: %d\n", o.f2()); 
    return 0; 
} 

結果:

$ g++ -o test2 test2.cpp && ./test2 
/tmp/ccahIuzY.o: In function `Base<&(int identity<10>())>::f()': 
test2.cpp:(.text._ZN4BaseIXadL_Z8identityILi10EEivEEE1fEv[_ZN4BaseIXadL_Z8identityILi10EEivEEE1fEv]+0xd): undefined reference to `int identity<10>()' 
collect2: error: ld returned 1 exit status 

私が専門化をコメントアウトすると、コードはコンパイルされ、期待どおりにリンクされます。また、私がBase<identity<10> >の代わりにBase<identity<Val> >を継承すると、コードは期待通りに機能します。

はここに試してみてください。http://coliru.stacked-crooked.com/a/9fd1c3aae847aaf7

私は何を欠場か?

+3

この問題はgccのバグのようです:それはコンパイルと打ち鳴らすと、ICCを使用して[OK]をリンクします。一般に、_identity()_という名前は、結果が引数と同じである変換に使用されます。 –

+0

@DietmarKühl「identity () 'は' X'を返します。 :-) – melpomene

+2

回避策: 'クラスDerived:public Base (identity <10>)>'。 [ライブデモ](http://melpon.org/wandbox/permlink/E4aRHqcZaac7vd3C) –

答えて

19

問題はgccのエラーであるようだ:コードがコンパイルされ、打ち鳴らす、ICC、およびEDGフロントエンドにリンクします。潜在的な回避策使用のいずれかを変更していないが、代わりに、関数のクラステンプレートidentityの使用次のようになります。

template<int I> 
struct identity { 
    operator int() { return I; } 
}; 

template<typename fn> 
class Base { 
public: 
    int f() { 
     return fn(); 
    } 
}; 
+0

関数テンプレートを 'inline'にしないこともできます。とにかく、重複したテンプレートのインスタンス化をリンカーが削除しないといけないのですか? – Etherealone

9

するのtypedefにそれを持ち上げると、まっすぐに動作しないクラス定義でそれをやって、なぜすなわち

typedef Base< identity<10> > base10; 

私はかなりわからない、それがコンパイルします。

http://coliru.stacked-crooked.com/a/f00b4f4d1c43c2b0

関連する問題