4

次の例は正常にコンパイルされますが、operator<<() の宣言と定義を分離する方法がわかりません。これはこの特定のケースです。

定義を分割しようとするたびに、友人が問題を引き起こし、gcc は operator<<() 定義が正確に 1 つの引数を取る必要があると不平を言います。

#include <iostream>
template <typename T>
class Test {
    public:
        Test(const T& value) : value_(value) {}

        template <typename STREAM>
        friend STREAM& operator<<(STREAM& os, const Test<T>& rhs) {
            os << rhs.value_;
            return os;
        }
    private:
        T value_;
};

int main() {
    std::cout << Test<int>(5) << std::endl;
}

Operator<<() には、さまざまな種類の出力ストリーム (std::cout、std::wcout、または boost::asio::ip::tcp::iostream) で動作する自由な最初のパラメーターがあるはずです。2 番目のパラメーターは、周囲のクラスの特殊なバージョンにバインドする必要があります。

Test<int> x;
some_other_class y;

std::cout << x; // works
boost::asio::ip::tcp::iostream << x; // works

std::cout << y; // doesn't work
boost::asio::ip::tcp::iostream << y; // works

その上、非メンバー関数を使用することは、非メンバー関数がクラスのプライベート属性にアクセスできないため、定義と宣言を分割することと同等ではありません。

4

5 に答える 5

4

最も簡単な方法は、おそらくこれらすべてのテンプレート オペレーターを友達にすることです。

#include <iostream>
template <typename T>
class Test
{
    public:
        Test(const T& value) : value_(value) {}

        template <typename STREAM, typename U>
        friend STREAM& operator<<(STREAM& os, const Test<U>& rhs);

    private:
        T value_;
};

template <typename STREAM, typename T>
STREAM& operator<<( STREAM& os, const Test<T>& rhs )
{
    os << rhs.value_;
    return os;
}
于 2010-05-12T15:17:57.330 に答える
1

私が達成できる最も近いのは

#include <iostream>

template <typename T>
class Test;

template <typename STREAM, typename T>
STREAM& operator<<(STREAM& os, const Test<T>& rhs);

template <typename T>
class Test {
public:
    Test(const T& value) : value_(value) {}

    template <typename STREAM, typename U>
    friend STREAM& operator<< (STREAM& os, const Test<U>& rhs);

private:
    T value_;
};

template <typename STREAM, typename T>
STREAM& operator<<(STREAM& os, const Test<T>& rhs) {
    os << rhs.value_;
    return os;
}

int main() {
    std::cout << Test<int>(5) << std::endl;
}

T によってパラメーター化されたものだけではなく、すべての operator<< をフレンドとして宣言します。問題は、関数を部分的に特殊化できないことです。使いたかった

template <typename STREAM>
friend STREAM& operator<< <STREAM, T> (STREAM& os, const Test<T>& rhs);

しかし、それは有効な構文ではありません。(まあ、部分特化は友達宣言できない)

于 2010-05-12T15:19:20.383 に答える
1

クラスの外で定義すべきではありませんか?

template <typename T>
class Test 
{  
    ...
    template <typename STREAM>
    friend STREAM& operator<<(STREAM& os, const Test<T>& rhs);
};

template <typename STREAM, typename T> 
STREAM& operator<<(STREAM& os, const Test<T>& rhs) 
{
    os << rhs.value_;
    return os;
}
于 2010-05-12T15:05:35.997 に答える
0

クラス Test のインスタンス化された型 T ごとに、さまざまな種類のストリームを操作できるテンプレート関数 operator<<() が公開されます。operator<<() 関数の最初のパラメーターは自由ですが、2 番目のパラメーターは固定されています。

例:

Test<int> x;
some_other_class y;

std::cout << x; // works
boost::asio::ip::tcp::iostream << x; // works

std::cout << y; // doesn't work
boost::asio::ip::tcp::iostream << y; // works

これが、Test クラスが機能するはずだった方法です。

于 2010-05-12T16:21:57.417 に答える
0

問題は、友人が提示するコードでは、最初の引数の型でのみパラメーター化されたテンプレート化された関数であることです。つまり、クラス テンプレートのインスタンス化する型 T ( it と呼びますmytype) ごとに、自由なテンプレート関数を宣言しています。

template <typename STREAM>
STREAM& operator<<( STREAM& os, Test<mytype> const & x );

重要な点は、 with type argumentTest<mytype>の特定のインスタンス化です。Testmytype

ストリーム型とテンプレートのインスタンス化型の両方でテンプレート化されたフレンド関数を本当に宣言したい場合は、Test2 つの引数でフレンドを宣言する必要があります。

一方でoperator<<、ストリーム型をパラメータ化しないことをお勧めします。同時に、クラスの中かっこ内で定義することをお勧めします。これには、わずかな利点があるためです (名前の検索規則が少し異なります)。

于 2010-05-12T16:00:14.930 に答える