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;
}

我的第二次尝试如下:

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;
}

此解决方案的问题不适用于继承 foo 的类型,因为T无法自动推断。

所以我可以跳过UT改用,在这种情况下,将从第二个参数推导出 T 并且参数 foro可以转换为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上的第二个直播

给定

#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 * 值”)保存到流中没有任何意义,因为该值(内存地址)在流读取时将毫无意义。

如果您正确地想要“保存指向的内容”,则在保存指针时应该保存一些内容,告诉“您正在保存什么类型的对象”,然后以多态方式保存对象,(通过调用虚函数)o导出的数据也被保存。同时,您还必须跟踪循环引用,以免多次保存同一个对象(并将其作为不同的对象加载回来),因此还需要“身份”。

要重新加载对象,您应该首先读取保存的描述类型的元数据,并在此基础上创建相应的对象,然后将其成员重新分配给提取时加载的数据。(或者如果只保存了一个标识,请将指针指向已重新创建的相应对象)。

所有这些东西都以serialization的名义出现。周围有很多解决方案,你可能应该用谷歌搜索那个键。

于 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 回答