【问题标题】:Type erasure for binary operations二进制操作的类型擦除
【发布时间】:2013-03-13 14:02:55
【问题描述】:

可以编写一个包装器,它采用任何支持特定操作的类型,例如

#include <iostream>

class Houdini
{
  struct I_Houdini_Impl
  {
    virtual void foo_impl(int x) const = 0;

    virtual ~I_Houdini_Impl() { }
  };

  template <typename T>
  struct Houdini_Impl : I_Houdini_Impl
  {
    Houdini_Impl(T const & t) : m_t(t) { }

    void foo_impl(int x) const { m_t.foo(x); }

    T m_t;
  };
public:
  template <typename T>
  Houdini(T const & t) : m_impl(new Houdini_Impl<T>(t)) { }

  void foo(int x) const { m_impl->foo_impl(x); }
protected:
private:

  std::unique_ptr<I_Houdini_Impl> m_impl;
};

class A
{
public:
  void foo(int x) const { std::cout << "A::foo(" << x << ")" << std::endl; }
};

class B
{
public:
  template <typename T>
  char foo(T const & t) const { std::cout << "B::foo(" << t << ")" << std::endl; return 'B';}
};

void houdini()
{
  A a;
  B b;
  Houdini ha(a);
  Houdini hb(b);

  ha.foo(7);
  hb.foo(8);
}

我可以在 Houdini 类中包装任何支持 const 方法 foo 的东西,该方法可以用 int 调用,无论它是普通成员函数(如 A 类)还是函数模板(如 B 类) ) (让我们暂时忽略 Houdini 应该表现出价值语义学)。到目前为止一切顺利,但我想做的是编写一个支持二进制操作的包装器,例如编写一个接受任何类型的包装器,并且您可以添加任意两个包装器,只要可以添加包装的对象并从添加中返回包装的返回对象:

class A { };
class B { };
class C { };

C operator+(A, B) { return C(); }

class Randi
{
public:
  template <typename T> Randi(T ) { }

/* magic stuff goes here */
};

void randi()
{
  A a;
  B b;

  Randi ra(a);
  Randi rb(b);

  Randi rc = ra + rb;
  // rc is a Randi-object that wraps an object of type C
}

如果我提前知道要存储什么类型,我可以通过写访问者来做到这一点,但这正是我想要做的。我需要解开两个对象,尝试在两个解开的对象上调用 operator+ 并再次包装结果,但我不知道该怎么做。

【问题讨论】:

  • 我会说用模板和魔法可以解决这个问题,但我不够聪明,不知道怎么做。
  • 根据您目前的描述,我认为您可能不走运。确定要使用哪些operator+ 的可能重载需要编译时所涉及类型的知识,但您已经专门删除了该类型信息。对于两个操作数必须是相同类型的情况,您也许可以这样做。

标签: c++ type-erasure


【解决方案1】:

考虑关注

class Number
{
virtual Number* sum(Number* other) = 0;
};

class Int
     : public Number
{
    virtual Number* sum(Number* other)
    {
        // hard to implement since we doesn't know the type of other
    }
};


class Double
     : public Number

{
    virtual Number* sum(Number* other)
    {
        // hard to implement since we doesn't know the type of other
    }
};

我们可以在 sum 实现中做 dynamic_casts 来分别处理每个案例,或者我们可以使用双重调度。

class Double;
class Int;

class Number
{
public:
    virtual Number* sum(Number* other) = 0;
protected
    virtual Number* sum(Int* other) = 0; 
    virtual Number* sum(Double* other) = 0; 
};

class Int
     : public Number
{
    virtual Number* sum(Number* other)
    {
        return other->sum(this);
    }

    virtual Number* sum(Int* other)
    {
        // implement int + int
    }

    virtual Number* sum(Double* other)
    {
        // implement int + double
    }
};


class Double
     : public Number

{
    virtual Number* sum(Number* other)
    {
        return other->sum(this);
    }


    virtual Number* sum(Int* other)
    {
        // implement double + int
    }

    virtual Number* sum(Double* other)
    {
        // implement double + double
    }
};

在机器人案例中,实现应该了解所有派生类。这意味着 Randi 类的 Houdini_Impl 模拟应该知道可能传递给 Randi 构造函数的所有其他类型,这是不可能的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多