Избегайте включения типов, чтобы обеспечить постоянное сворачивание

Я пытаюсь найти иерархию классов, которая позволяет реализовать заполнители для регистров процессора и операций над ним. Это также должно позволить складывать константы во время выполнения. Для простоты я рассмотрю только одну операцию, здесь умножение. Заполнители и константы должны быть доступны равномерно, то есть иметь общий базовый класс.

Код ниже определяет следующие классы:

class A: Базовый класс для заполнителей (регистров) и констант

class B: Место для регистра (его структура содержит название)

class C: База всех констант

class CI: int постоянная

class CF: float постоянная

#include <iostream>
#include <memory>
#include <cassert>

class A {
public:
virtual ~A(){}
};

class B : public A {
};

class C : public A {};

class CI : public C {
public:
typedef int Type_t;
int getValue() {return 1;}
};

class CF : public C {
public:
typedef float Type_t;
float getValue() {return 1.1;}
};typedef std::shared_ptr<A> Aptr;
typedef std::shared_ptr<B> Bptr;
typedef std::shared_ptr<C> Cptr;
typedef std::shared_ptr<CI> CIptr;
typedef std::shared_ptr<CF> CFptr;template<class T, class T2> struct promote {};
template<> struct promote<float,int>   { typedef float Type_t; };
template<> struct promote<float,float> { typedef float Type_t; };
template<> struct promote<int,float>   { typedef float Type_t; };
template<> struct promote<int,int  >   { typedef int   Type_t; };template<class T1, class T2>
typename promote<typename T1::element_type::Type_t,
typename T2::element_type::Type_t>::Type_t
mul_const( const T1& c1 , const T2& c2 )
{
std::cout << c1->getValue() * c2->getValue() << "\n";
return c1->getValue() * c2->getValue();
}template<class T>
std::shared_ptr<T> get(const Aptr& pA) {
return std::dynamic_pointer_cast< T >( pA );
}Aptr create_A(float f) { return std::make_shared<A>(); }
Aptr create_A(int i)   { return std::make_shared<A>(); }Aptr mul_const( const Cptr& cp1 , const Cptr& cp2 )
{
if (auto c1 = get<CI>(cp1))
if (auto c2 = get<CF>(cp2)) {
return create_A( mul_const(c1,c2) );
}
if (auto c1 = get<CF>(cp1))
if (auto c2 = get<CI>(cp2)) {
return create_A( mul_const(c1,c2) );
}
if (auto c1 = get<CI>(cp1))
if (auto c2 = get<CI>(cp2)) {
return create_A( mul_const(c1,c2) );
}
if (auto c1 = get<CF>(cp1))
if (auto c2 = get<CF>(cp2)) {
return create_A( mul_const(c1,c2) );
}
assert(!"oops");
}Aptr mul( const Aptr& pA1, const Aptr& pA2 )
{
if (auto c1 = get<C>(pA1))
if (auto c2 = get<C>(pA2))
{
return mul_const(c1,c2);
}
}int main()
{
Aptr pA1( new CF );
Aptr pA2( new CI );

Aptr result = mul( pA1, pA2 );
}

Проблема, с которой я столкнулся с приведенным выше кодом, заключается в функции Aptr mul_const( const Cptr& cp1 , const Cptr& cp2 ), Он содержит в основном переключение типов для всех возможных комбинаций постоянных типов. Это работает, но я хотел бы знать, если это можно сделать более элегантно?

0

Решение

Я думаю, вы могли бы сделать то, что делает компилятор, и преобразовать другой параметр в float, когда один из них float. Вам, вероятно, понадобится новая функция для выполнения преобразования и isFloat (или isInt). Я не уверен, что это дает тебе такую ​​большую пользу, правда …

// Add two virtual member functions here:
class C : public A {
public:
virtual bool isInt() = 0;
virtual float getAsFloat() = 0;
};

Затем выполните:

class CI : public C {
public:
typedef int Type_t;
int getValue() {return 1;}
float getAsFloat() { return getValue(); }
bool isInt() { return true; }
};

class CF : public C {
public:
typedef float Type_t;
float getValue() {return 1.1;}
float getAsFloat() { return getValue(); }
bool isInt() { return false; }
};

Теперь ваш mul_const становится:

Aptr mul_const( const Cptr& cp1 , const Cptr& cp2 )
{
if (cp1.isInt() && cp2.isInt())
{
CIptr c1 = get<CI>(cp1));
CIptr c2 = get<CI>(cp2));
std::cout << c1->getValue() * c2->getValue() << "\n";
return CIptr(c1->getValue() * c2->getValue());
}
else
{
std::cout << cp1->getAsFloat() * cp2->getAsFloat() << "\n";
return CFptr(cp2->getAsFloat() * cp2->getAsFloat());
}
// This becomes unreachable... Probably OK to delete.
assert(!"oops");
}
[И я думаю, что некоторые части шаблона могут быть удалены …]
1

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

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