3

operator<< をオーバーロードして、 で動作できるようにしたいと思いshared_ptrます。

template<typename T>
struct foo
{
    virtual foo& operator<<(const T& e) = 0;
};

foo<int> f1;
f1 << 1;

std::shared_ptr<foo<int>> f2(new foo<int>());
f2 << 1;

私の最初の試みは次のとおりですが、問題は、どのクラスの動作も有効にすることです。

template<typename T, typename U>
const std::shared_ptr<T>& operator<<(const std::shared_ptr<T>& o, const U& e)
{
    *o << e;
    return o;
}

私の2番目の試みは次のとおりです。

template<typename T, typename U>
const std::shared_ptr<foo<T>>& operator<<(const std::shared_ptr<foo<T>>& o, const U& e)
{
    *o << e;
    return o;
}

このソリューションの問題は、T自動的に推定できないため、foo を継承する型では機能しません。

したがって、スキップUして代わりに使用することもできますT。その場合、 T は 2 番目の引数から推定され、 の引数oは に変換できますfoo<T>

template<typename T, typename U>
const std::shared_ptr<foo<T>>& operator<<(const std::shared_ptr<foo<T>>& o, const T& e)
{
    *o << e;
    return o;
}

ただし、次の場合は機能しません。

struct c    
{    
};

struct a
{
    a();
    a(c); // implicit conversion
};

struct b
{
    operator a(); // implicit conversion
};

auto f = std::make_shared<foo<a>>();
f << c; // doesn't work.
f << b; // doesn't work.

実用的なソリューションを作成する方法についてのアイデアはありますか?

4

3 に答える 3

3

一部のオプションについては、https://ideone.com/26nqrで 2 回目のライブをご覧ください

与えられた

#include <iostream>
#include <memory>
using namespace std;

template<typename T> struct foo {
    virtual foo& operator<<(const T& e) const { std::cout << "check foo\n"; }
};

//////
// derived instances

struct derived : foo<int> {
    virtual derived& operator<<(const int& e) const { std::cout << "check derived\n"; }
};

template<typename T> struct genericDerived : foo<T> {
    virtual derived& operator<<(const T& e) const { std::cout << "check genericDerived\n"; }
};

シンプル: テンプレート テンプレート引数

template<typename T, typename U, template <typename> class X>
const std::shared_ptr<X<T>>& operator<<(const std::shared_ptr<X<T>>& o, const U& e)
{
    *o << e;
    return o;
}

int main()
{
    auto f = make_shared<foo<int>>();
    f << 1;

    auto d = make_shared<derived>();
    d << 2; // compile error

    auto g = make_shared<genericDerived<int>>();
    g << 3; // SUCCESS!
}

コンプリーター: SFINAE

上記は派生クラスをキャッチしません (ケース 2)。それを行うには、私はに頼ります

#include <type_traits>
namespace detail
{
    template<typename Foo, typename T>
        const std::shared_ptr<Foo>& dispatch_lshift(
                  const std::shared_ptr<Foo>& o, const T& e, 
                  const std::true_type& enabler)
        {
            *o << e;
            return o;
        }
}

template<typename Foo, typename T>
    const std::shared_ptr<Foo>& operator<<(const std::shared_ptr<Foo>& o, const T& e)
{
    return detail::dispatch_lshift(o, e, std::is_convertible<Foo*, foo<T>* >());
}

int main()
{
    auto f = make_shared<foo<int>>();
    f << 1;

    auto d = make_shared<derived>();
    d << 2;

    auto g = make_shared<genericDerived<int>>();
    g << 3;

    auto x = make_shared<int>();
    // x << 4; // correctly FAILS to compile    
}
于 2012-01-02T13:22:13.860 に答える
1

あなたは、C++ を Java のように見せるという悪い舞台に身を置くことになるかもしれません。

C++ のポインター、値、および参照は異なる型であり、異なるセマンティクスと操作を持っています。一般に、これらを混同して同じ構文にすることはお勧めできません。ポインターはその値ではありません: 参照する型以外の型を指すことができます (通常、継承の場合)。したがって、一般的には、ポインターの逆参照を明示的なままにしておく方が適切です。

ただし、「ポインタ値」(「pointe* d * value」ではない) をストリームに保存しても意味がありません。その値 (メモリ アドレス) はストリームの読み取りでは意味がないからです。

「ポイントされているものを適切に保存」したい場合は、ポインターを保存するときに、「保存しているオブジェクトのタイプ」を示す何かを保存し、オブジェクトをポリモーフィックに保存する必要があります (仮想関数の呼び出しを通じて) o派生データも保存されます。一方、同じオブジェクトを複数回保存しないようにする (そして、別のオブジェクトとしてロードし直す) ためには、循環参照も追跡する必要があるため、「ID」も必要です。

オブジェクトを再度ロードするには、まずタイプを記述するために保存したメタデータを読み取り、それに基づいて対応するオブジェクトを作成し、抽出時にロードされたデータにそのメンバーを再割り当てする必要があります。(または、ID だけが保存されている場合は、既に再作成された対応するオブジェクトへのポインターをポイントします)。

すべての詰め物は、シリアライゼーションの名前の下にあります。周りには多くの解決策があります。おそらく、そのキーを Google で検索する必要があります。

于 2012-01-02T13:25:34.360 に答える
-1

最初のソリューションを次のように使用できますenable_if(私は C++03 名前空間を使用しています):

template <typename T>
class is_funky : public boost::false_type {};

template <typename S>
class is_funky< Foo<S> > : public boost::true_type {};

template<typename T, typename U>
typename boost::enable_if< is_funky<T>, const boost::shared_ptr<T>& >::type 
operator<<(const boost::shared_ptr<T>& o, const U& e)
{
    *o << e;
    return o;
}

実動コードよりも適切な名前を見つけたいと思うかもしれませんが、is_funkyそれはコンテキストに依存します。

于 2012-01-02T13:18:30.027 に答える