2013-03-14 23 views
5

メンバ型を定義するテンプレートクラスがあります。それはstd::mapがそれ自身のテンプレート引数に基づいてvalue_typeを定義する方法と似ていますが、私の場合は型がより複雑なので入れ子になったクラスとして定義されています。メンバ型テンプレートのフリー関数をオーバーロードする方法

デバッグの場合、そのタイプにoperator<<を定義します。しかし、コンパイラは、外側のテンプレートのテンプレートパラメータを推論できないと私に伝えます。

私の実際のコードは、次の例のように工夫が、この不自然な例では、私が試したのアプローチを実証し、それが失敗したかされていません。

#include <iostream> 

template <typename Value> class Outer; 

template <typename Value> 
std::ostream &operator<<(std::ostream &, const typename Outer<Value>::Inner &); 

template <typename Value> 
class Outer { 
    public: 
    struct Inner { 
    Value x; 
    }; 

    void PrintSomething(Value v) { 
    // the real program does something useful with the inner class, of course 
    Inner inner = { v }; 
    std::cout << "Inner = " << inner << std::endl; // <---- THIS SAYS IT CAN'T FIND operator<< 
    }; 
}; 

template <typename Value> 
std::ostream &operator<<(std::ostream &s, const typename Outer<Value>::Inner &v) { 
    return s << v.x; 
} 

int main() { 
    Outer<int> o; 
    o.PrintSomething(42); 
    return 0; 
} 

この問題を再現するための完全なサンプルです。コンパイラ(私はそれらのうち3つを試しました)は、operator<<のオーバーロードがなく、タイプOuter<int>::Innerの第2引数を取ると言います。他のオーバーロードのない別の関数を使って同じことを試みると、代わりにC2783: could not deduce template argument for 'identifier'と表示され、gccとclangは2番目の引数Outer<int>::Innerを必要とするオーバーロードはないと言い続けます。

だから、が右引数(それがメンバーとして定義することはできません)だとしてoperator<<はどのValueためOuter<Value>::Innerを取って定義する方法はありますか?

注:いくつかのコンパイラでコンパイルする必要があり、その中にはC++ 11の機能がないものがありますので、C++ 03にする必要があります。

+0

「インナー」のインラインフレンドにしてください。 – Xeo

+0

@ Xeo:あなたはそれを答えることができますか?それは実行可能なアイデアと聞こえる。 –

+0

私はあなたがそれを行うことができるか分からない。あなたの近くにある[この質問](http://stackoverflow.com/questions/9649904/could-not-deduce-template-argument-pointer-to-member)を参照してください。 – Synxis

答えて

6

あなたが持っているものは、いわゆるであり、推論不可能な文脈です。 Valueさんはどのように推測できますか?クラステンプレートを部分的に特殊化することができます。コンパイラはインスタンス化(可能な限り無限に存在する)を試してみることも事実上不可能です。

回避方法には2通りあります。InnerOuterから取り除くか、operator<<をインラインフレンドにします。後者は、人々が行く通常の方法です。

template<class T> 
struct Outer{ 
    struct Inner{ 
    T value; 
    friend std::ostream& operator<<(std::ostream& os, Inner const& v){ 
     return os << v.value: 
    } 
    }; 
    // ... 
}; 
+0

私は実際に 'operator <<'を直接オーバーロードしていませんでしたが、私のロギング関数に特有の同様の関数をオーバーロードしていました。そして、通常の機能のために、インラインフレンドは、内部を含むクラス内の他のオーバーロードを隠します。だから私は内部に何か違うオーバーロードを呼出したいときには、間接的に使う必要がありました。しかし、それは小さなハードルです。 –

関連する問題