2013-03-13 2 views
2

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

#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-класса, который поддерживает сопзЬ-метод Foo, который можно назвать Жека в междунар, независимо, если это обычная функция член (как в классе А) или шаблон функции (как и в классе 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 + на двух развернутых объектах и ​​снова обернуть результат, но я не могу понять, как это сделать.

+0

Я бы сказал, что с помощью шаблонов и магии это можно решить, но я недостаточно умен, чтобы знать, как это сделать. –

+0

Я думаю, вам может быть не повезло, учитывая ваше текущее описание. Определение того, какие возможные перегрузки для 'operator +' для использования потребует знания времени компиляции соответствующих типов, но вы специально удалили эту информацию о типе. Возможно, вы сможете сделать это для случаев, когда оба операнда должны быть одного типа. –

ответ

0

Рассмотрим следующие

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

Мы можем сделать 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 
    } 
}; 

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

Смежные вопросы