2010-12-07 5 views
2

私は値を保持するテンプレートクラスを持っています。クラスにコンストラクタを追加して、下の例のような暗黙の変換を可能にすることは可能ですか?テンプレートクラスにコンストラクタを追加します

これを行うには良い方法がありますか?

#include <string> 

template<typename T> 
class Value 
{ 
    public: 
    Value(const T& value) : m_value(value) { }; 
    private: 
    T m_value; 
}; 

// I thought adding something like this would do the trick but it does not work: 
/* 
template<> 
class Value<std::string> 
{ 
    public: 
    Value(const char *sz) : m_value(sz) { }; 
} 
*/ 

void f(const Value<std::string> &s) 
{ 
} 

int main() 
{ 
    f(std::string("hello")); 

    // I want to have this working: 
    f("hello"); 
} 

答えて

4

は、2つのユーザ定義の変換を必要とする文字列リテラルでf(const Value<std::string>&)を呼び出す(const char[] ==>std::string ==>Value<std::string>)関数パラメータを一致させるために、標準の一方のみ1つを許可します。
私はそれを解決するために2つの可能性を見出します:コンストラクタに過負荷をかけるか、またはf()をオーバーロードしてください。

後者が不可能であるため、前者について質問していると仮定すると、コンストラクタをオーバーロードする方法はいくつかあります。

クラステンプレートのメンバー関数は、呼び出された場合にのみコンパイルされ、Tが特定の型のときにのみコンパイルされるコンストラクタを追加することができます。もちろん、テンプレートのユーザーが他のタイプのテンプレートを呼び出すと、エラーになります。 しかし、代わりにこの問題を見てのあなたは、コンストラクタにメンバーのテンプレートを作成することで、それを受け入れることもできます(もちろん、だけでなく、T自体)Tに変換することができますどんな

template<typename U> 
Value(const U& value) : m_value(value) { }; 

その方法は、許可されていますU

また、std::stringのクラスを特化することもできます。残念ながら、クラス全体をに特化しなければならないのは、個々のメンバーの選択的な特化がないからです。この場合、すべてのコードを共通(おそらくprivate基底クラスValueValue基本テンプレートに移して、基本クラスのコンストラクタに転送するコンストラクタを定義するだけです)、Value<std::string>const char*という別のコンストラクタを追加します。

+0

私はそれが暗黙的に変換可能だと思ったが、コンパイラ(g ++)参照の無効な初期化)。 – rve

+0

といいえ、文字列はプレースホルダーではありません – rve

+0

@rve:申し訳ありませんが、これは私の脳の一部です。私はあなたがCの文字列で 'f()'を呼びたいと思っていませんでした。私は私の答えを修正します。 – sbi

1

あなたはそのようなクラスに追加することはできませんが、クラス全体を専門にすることはできます。

1

this試し:

template<typename T> 
class Value 
{ 
    public: 
    Value(const T& value) : m_value(value) { } 
    Value(const char* a): m_value(a){} // add this 
    private: 
    T m_value; 
}; 
+0

があります確かにそれは動作しますが、値にはあまり意味がありません rve

+0

@rve:私の唯一の目的は、コンパイルエラーからあなたのコードを解放することでした;-) –

2

あなたがすることはできません。これは、C++の設計者による明示的な決定です。その理由は、コンパイラは可能な変換のために狩りに行く必要があるだろう、と一般的に、これは無限狩りだろうということである。

確かにconst char[] ==>std::string ==>Value<std::string>は論理的だと思いますが、コンパイラにはがありません。ちょうどconst char[] ==>ですか? ==>Value<std::string>、それは真ん中にタイプを見つける必要があります。例えば、Foo::Foo(const char*)コンストラクタとFoo::operator Value<std::string>() constを持つどこかにclass Fooが存在する可能性があります。それも効くだろう。

ご覧のとおり、Fooを指すconst char[]またはValue<std::string>には何もありません。したがって、コンパイラは盲目の狩りに行きます。

Valueの作者として、あなたは選択肢があります。あなたは、文字列:: stringは受け入れるValue<std::string>ははstdあらゆるタイプ::から構成することができるコンパイラに知らせることができます。

template<typename T> 
class Value 
{ 
    public: 
    Value(const T& value) : m_value(value) { }; 
    // Intentionally not "explicit" 
    template<typename U> Value(const U& value) : m_value(value) { }; 
    private: 
    T m_value; 
}; 

を今、あなたはf("hello")としてvoid f(const Value<std::string> &s)を呼び出す場合、単一の暗黙的な変換Value<std::string>::Value<const char*>(const char* const&)

関連する問題