2016-07-29 29 views
5

std::string引数の特殊なコンストラクタを作成しようとしていますが、もう1つは文字列引数で呼び出すときに常に使用されます。C++コンストラクタテンプレートの特殊化

struct Literal : Expression 
{  
    template <typename V> 
    Literal(V val) 
    { 
     value = val; 
    } 
}; 

template <> 
Literal::Literal(std::string const& val) 
{ 
    value = val.c_str(); 
} 

両方がクラス内で定義されている場合にのみ専門は、クラス外で定義されたクラスの外、または掲載例のように、両方の、重要ではありません。std::stringで呼び出された場合、割り当てvalue = valはA与えますコンパイラエラー。

std::stringのこのコンストラクタテンプレートを正しく特殊化するにはどうすればよいですか?

+0

あなたは[値]を宣言していませんでした。 _main.cpp:12:9:error: 'value'がこのスコープで宣言されていませんでした。 value = val; _ –

+0

@HenriqueBarcelos 'ATL :: CComVariant value'は' Expression'で宣言されています。 。簡潔にするために関連するテンプレートを投稿しただけです。 –

+0

私は 'value'が基本クラスで定義されていると仮定しています。 – Bathsheba

答えて

6

あなたはそうではありません。

コンストラクタLiteral(const std::string&)をオーバーロードする必要があります。これはstruct宣言で実行できます。

コンパイラは、テンプレート以外のオーバーロードを常にテンプレート1より前に一致させようとします。

+0

編集はありません。テンプレート以外のコンストラクタは表示されません。 – kfsone

+0

申し訳ありませんが、私は答えをより明確にしました。 – Bathsheba

+0

私の混乱はこれです:彼は1つのコンストラクタしか持っていません。テンプレート化されているので、彼はそれを特殊化しようとしています。そのため、クラス内のテンプレート宣言/機会? – kfsone

1

何度も、オーバーロードが解決策である場合、人々は完全な専門化を定義しようとします。しかし、過負荷ははるかに良い解決策かもしれません。あなたの場合は、私は文字列パラメータで新しいコンストラクタを作成します。 オーバーロード解決では基本テンプレートのみが考慮されることに注意してください。次の記事では、この考え方を理解する良いの参照です: http://www.gotw.ca/publications/mill17.htm

UPDATE:

とにかく

、私の答えを改善するには、次の基本テンプレートコンストラクタを試みることができる:

template <typename V> 
Literal(V const& val) 
{ 
    value = val; 
} 
4

によると、 standard, 14.8.2.1関数呼び出しからのテンプレート引数の控除[temp.deduct.call] Pがテンプレートパラメータで、Aがその位置の関数呼び出し引数です。

01だから、

std::string s{"hello"}; 
const std::string& sr{s}; 
Literal l(sr); 

A(SR)与えられた

2 If P is not a reference type:

If A is an array type, the pointer type produced by the array-to-pointer = standard conversion ([conv.array]) is used in place of A for type deduction; otherwise,

If A is a function type, the pointer type produced by the function-to-pointer standard conversion ([conv.func]) is used in place of A for type deduction; otherwise,

If A is a cv-qualified type, the top-level cv-qualifiers of A's type are ignored for type deduction.

If P is a cv-qualified type, the top-level cv-qualifiers of P's type are ignored for type deduction. If P is a reference type, the type referred to by P is used for type deduction. [...]

const std::string&ですが、const性を考え、そのコンパイラはstd::stringとはみなされません。これはあなたに合っています

template <typename V> 
Literal(V val) 
{ 
    value = val; 
} 

ですので、この専門用語を使用しています。

template<> 
Literal(std::string val) 

コンパイラにはこの特殊化がありますが、これはおそらく移動のセマンティクスを使用する必要があります。

#include <iostream> 
#include <string> 

struct S { 
    template<typename T> 
    S(T t) { std::cout << "T t\n"; } 

    std::string value_; 
}; 

template<> 
S::S(std::string value) { 
    std::cout << "string\n"; 
    value_ = std::move(value); 
} 

template<> 
S::S(const std::string&) { 
    std::cout << "const string&\n"; 
} 

int main() { 
    S s1(42); 

    std::string foo{"bar"}; 
    const std::string& foor = foo; 
    S s2(foo); 
    S s3(foor); 
} 

http://ideone.com/eJJ5Ch

+0

ありがとう、これは正解です!しかし、私はgcc toolchainを使ってこの種の問題を抱えていませんでした。 clangに移植するときだけ、答えを探す必要がありました。 – foxfireee

関連する問題