Стирание типа для бинарных операций

Можно написать оболочку любого типа, которая поддерживает определенную операцию, например

#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) (и давайте пока проигнорируем, что Гудини должен показывать семантику значения). Пока все хорошо, но я хотел бы написать обертку, которая поддерживает двоичные операции, например написать обертку, которая принимает любой тип, и вы можете, скажем, добавить любые две обертки, если можно добавить обернутые объекты и вернуть обернутый возвращаемый объект из дополнения:

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 + для двух развернутых объектов и снова обернуть результат, но я не могу понять, как это сделать.

2

Решение

Подумайте о следующем

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

Мы можем делать динамические трансляции в суммированной реализации, чтобы обрабатывать каждый случай отдельно, или мы можем использовать двойную диспетчеризацию.

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

В случаях ботов реализации должны знать обо всех производных классах. Это означает, что аналог Houdini_Impl для класса Randi должен знать обо всех других типах, которые могут быть переданы конструктору Randi, что невозможно.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]