2011-11-17 12 views
15

int x = fromString("test")は 'ValueTypeに'なぜC++でテンプレートタイプが割り当てられないのですか?

int x = fromString<int>("test")のためのテンプレート引数を推定できませんでした:

を期待通りに正常に動作し、なぜここにコンパイラ闘争はいますか?私は、この愚かな例だけでなく、あらゆる種類の本当のテンプレート関数でそれを見ることができます。それは言語の特徴でなければなりませんが、何ですか?

+10

はなぜ "のtoString" と呼ばれるintに変換することができます何かありますか? –

+2

[この質問](http:// stackoverflow。com/questions/442026/function-overloading-by-return-type)も同様の問題について説明しています。 –

+0

"ちょうどそうではありません"。これはコンパイラではなく言語であることに注意してください。実際には、コンパイラが一般的なケースで正しく動作するためには難しいため、言語では特に指定されていません。 –

答えて

12

C++は戻り値の型推論を行いません。すなわち、それがintに代入されているという事実は、テンプレートパラメータの減算には使用されません。

(他の誰かがすでに過負荷にキャスト溶液を提示するので、編集を削除しました。)

+1

ありがとうございます。私はそれを必要としません、それはちょっと刺激的な癖の一つに過ぎず、私は理由を理解したいと思っていました。 –

1

あなたのテンプレートが自動的にあなたがここでそれを追加する必要が理由である推定することはできませんテンプレートの戻り値の型を持っているように見えます。例えば悪い選択に加えて

+0

遅延戻り型宣言(または呼び出されたもの)は、異なる目的を持っています。関数の引数の型に基づいて戻り値の型を宣言することができます。それは、引数がスコープになるまで戻り値の型を宣言するだけです。呼び出し元の使用方法の結果の種類を推測することはできません。 – visitor

+0

コメントのおかげで、私は私の投稿から削除します:-) – Firedragon

0

(おそらくint x = to<int>("1235")ではなくtoStringを持っていることは理にかなっています)、問題は、[1]戻り値の型は、オーバーロードの解決や型推論に参加しないということです。

// assuming template <typename T> T to(std::string): 
// 
f(to("123"));   // where there are two overloads f(int), f(double) 
int x = 1.5 * to("123"); // T == int? T == double? 
to("123");    // now what? returned object can be ignored! 

ので、決定は戻り値の型は、オーバーロードの解決や型推論に参加しないことである。この理由は、式が戻り値の型が推論することができない多くの場所で使用することができるということです。

[1]このルールには1つの例外があります。これは、オーバーロードが宛先ポインタまたは明示的キャストのいずれかによって選択される必要がある複数のオーバーロードを伴う関数ポインタの評価ですが、他のコンテキストでは使用されません。

void f(); 
void f(int); 
void g(void (*)()); 
void g(void (*)(int)); 

void (*p1)() = &f;  // overload selected based on destination type 
void (*p2)(int) = &f; 
g((void (*)(int))&f); // overload selected based on explicit cast 
+0

"関数ポインタ" - メンバ関数へのポインタを含む。 –

16

戻り値の型に基づいて推論することはできません。ただし、オーバーロードされたキャスト演算子を使用して、同様の構文を使用して回避策を実装することができます

#include <iostream> 
#include <sstream> 
#include <string> 
using namespace std; 

class FromString{ 
private: 
    string m_data; 
public: 
    FromString(const char*data) : m_data(data) {} 

    template<typename T> 
    operator T(){ 
     T t; 
     stringstream ss(m_data); 
     ss >> t; 
     return t; 
    } 

}; 

template<> FromString::operator bool(){ 
    return (m_data!="false"); //stupid example 
} 

int main(){ 

    int ans = FromString("42");  
    bool t = FromString("true"); 
    bool f = FromString("false"); 

    cout << ans << " " << t << " " << f << endl; 

    return 0; 
} 

出力:機能の

42 1 0 
+0

ユニバーサル変換機能、大!しかし、 'operator ='は 'friend 'にはなり得ないので、これが最善の解決策であると思います。 – Potatoswatter

0

戻り値の型は、オーバーロードの解決ではなく、他の方法に依存していますまわり。 operator=は通常明示的なoperator=が定義されている場合を除いて(スタンドアロンとしてもメンバとしても関係なく)、等しいLHS/RHS引数タイプに対してのみ存在します。operator=は通常、同じ引数タイプに対してのみ存在します。operator=

したがって、オーバーロードの解像度はoperator=(int &, int)で、関数からの戻り値がintに変換可能かどうかを確認します。 operator intのテンポラリを返す場合、operator inttemplate<typename T> operator Tの一般形式であっても、これは許容可能な解像度です。

したがって:

template<typename T, typename U> 
U convert_impl(T const &t); 

template<typename T> 
struct convert_result { 
    convert_result(T const &t) : t(t) { } 
    template<typename U> operator U(void) const { return convert_impl<U>(t); } 
    T const &t; 
}; 

template<typename T> 
convert_result<T> convert(T const &t) { return t; } 
関連する問題