2011-01-20 24 views
3

とは一致しませんで:は、テンプレート関数

#include <string> 

void f(char const*, char const* = "") { 
} 

template<class StringType1,class StringType2> inline 
void g(StringType1 const &s1, StringType2 const &s2 = "") { 
    f(s1.c_str(), s2.c_str()); 
} 

template<class StringType> inline 
void h(StringType const &s1, StringType const &s2 = "") { 
    f(s1.c_str(), s2.c_str()); 
} 

int main() {    
    std::string s; 
    g(s); // error: no matching function for call to ‘g(std::string&)’ 
    h(s); // OK 
    return 0; 
} 

それは2つのテンプレート引数を持っているので、コンパイラはg()への呼び出しと一致していないが、それはh()うまくマッチします。どうして?

はFYI:私のコードベースは、実際には、いくつかの、高度に専門的な文字列クラスを使用していますので、私は第一及び第二引数が異なる文字列型であるかもしれない最大の柔軟性を可能にします。

答えて

7

コンパイラは、StringType2が想定されていることは考えていません。

g<std::string, std::string>(s); 

これを正しく動作させるには、次のようなコードで呼び出す必要があります。

0

g()は、StringType2がc_str()メンバーメソッドを提供しないconst char [](またはそれと類似した変形)であると推定されるため、拒否されます。どちらの場合でも、StringTypeがstd :: stringになっているので、h()は正常に一致します。

詳細なメタプログラミング手法を調べる必要がありますが、これは完全に可能である必要があります。

編集:明らかにデフォルトのargsはテンプレートタイプの控除などには参加しません。いずれにしても、部分的な特殊化のように、これを達成するために別のテクニックを使用する必要があります。

+1

この説明は正しいとは思いません。 AFAIK SFINAEは関数の本体を調べません。むしろ、私がずっと前に発見したように(Johannesは理由を説明するのを助けましたが、覚えていません)、引数のデフォルトはテンプレート引数を推論するために使用されません。つまり、デフォルトの引数を持つfoo()(def値42)は、テンプレートargの控除に関してfoo(42)を呼び出すのと異なります。コンパイラによって後者に書き直されていると思っていたので、私には驚きました。 –

関連する問題