Я постараюсь сделать этот вопрос настолько коротким, насколько смогу, но есть достаточный объем кода, который нужно показать, чтобы понять, чего я пытаюсь достичь и как решить мою текущую проблему.
Вот мои оригинальные объявления классов со всеми их конструкторами:
Register.h - Оригинальная версия
#include <bitset>
#include <cassert>
#include <cstdint>
#include <iostream>
typedef std::uint8_t u8;
typedef std::uint16_t u16;
typedef std::uint32_t u32;
typedef std::uint64_t u64;
const u16 BYTE = 0x08, WORD = 0x10, DWORD = 0x20, QWORD = 0x40;
typedef std::bitset<BYTE> Byte;
typedef std::bitset<WORD> Word;
typedef std::bitset<DWORD> DWord;
typedef std::bitset<QWORD> QWord;
template<typename T>
void getByteFrom(T val, u8 idx, u8& res) {
res = ((val >> (idx * 8) & 0xff));
}
template<typename T>
void getWordFrom(T val, u8 idx, u16& res) {
res = ((val >> (idx * 16) & 0xffff));
}
template<typename T>
void getDWordFrom(T val, u8 idx, u32& res) {
res = ((val >> (idx * 32) & 0xffffffff));
}
template<typename T>
struct Register {
T data;
Register() = default;
};
struct Reg8 : public Register<u8> {
u8 value; // must be declared before std::bitset<T>
Byte bits;
// Default 0 Initialized Constructor
Reg8() : value{ 0 }, bits{ value } { this->data = 0; }
// Constructors by Register Sized Values
explicit Reg8(u8 val) : value{ val }, bits{ value } {
this->data = value;
}
explicit Reg8(u16 val) : value{ static_cast<u8>( val ) }, bits{ value } {
this->data = value;
}
explicit Reg8(u32 val) : value{ static_cast<u8>( val ) }, bits{ value } {
//this->data = value;
}
explicit Reg8(u64 val) : value{ static_cast<u8>( val ) }, bits{ value } {
//this->data = value;
}
Reg8(u16 val, u8 idx ) {
assert( idx == 0 || idx == 1 );
getByteFrom(val, idx, this->value);
bits = value;
this->data = value;
}
Reg8(u32 val, u8 idx) {
assert(idx <= 0 && idx >= 3);
getByteFrom(val, idx, this->value);
bits = value;
this->data = value;
}
Reg8(u64 val, u8 idx) {
assert(idx <= 0 && idx >= 7);
getByteFrom(val, idx, this->value);
bits = value;
this->data = value;
}
// Constructors by Register Types
template<typename T>
explicit Reg8(Register<T>* reg) {
this->value = static_cast<u8>( reg->data );
this->bits = value;
}
};
struct Reg16 : public Register<u16> {
u16 value; // must be declared before std::bitset<T>
Word bits;
// Default 0 Initialized Constructor
Reg16() : value{ 0 }, bits{ value } { this->data = 0; }
// Constructors by Register Sized Values
explicit Reg16(u16& val) : value{ val }, bits{ value } {
this->data = value;
}
explicit Reg16( u8& val) : value{ val }, bits{ value } {
this->data = value;
}
explicit Reg16(u32& val) : value{ static_cast<u16>(val) }, bits{ value } {
this->data = value;
}
explicit Reg16(u64& val) : value{ static_cast<u16>(val) }, bits{ value } {
this->data = value;
}
Reg16( u32 val, u8 idx) {
assert(idx == 0 || idx == 1);
getWordFrom(val, idx, this->value);
bits = value;
this->data = value;
}
Reg16(u64 val, u8 idx) {
assert(idx <= 0 || idx <= 3);
getWordFrom(val, idx, this->value);
bits = value;
this->data = value;
}
// Constructors by Register Types
template<typename T>
explicit Reg16(Register<T>* reg) {
this->value = static_cast<u16>(reg->data);
this->bits = value;
}
};
struct Reg32 : public Register<u32> {
u32 value; // must be declared before std::bitset<T>
DWord bits;
// Default 0 Initialized Constructor
Reg32() : value{ 0 }, bits{ value } { this->data = 0; }
// Constructors by Register Sized Values
explicit Reg32(u32& val) : value{ val }, bits{ value } {
this->data = value;
}
explicit Reg32( u8& val) : value{ val }, bits{ value } {
this->data = value;
}
explicit Reg32(u16& val) : value{ val }, bits{ value } {
this->data = value;
}
explicit Reg32(u64& val) : value{ static_cast<u32>(val) }, bits{ value } {
this->data = value;
}
Reg32(u64 val, u8 idx) {
assert(idx == 0 || idx == 1);
getDWordFrom(val, idx, this->value);
bits = value;
this->data = value;
}
// Constructors by Register Types
template<typename T>
explicit Reg32(Register<T>* reg) {
this->value = static_cast<u32>(reg->data);
this->bits = value;
}
};
struct Reg64 : public Register<u64> {
u64 value; // must be declared before std::bitset<T>
QWord bits;
// Default 0 Initialized Constructor
Reg64() : value{ 0 }, bits{ value } { this->data = 0; }
// Constructors by Register Sized Values
explicit Reg64(u64& val) : value{ val }, bits{ value }{
this->data = value;
}
explicit Reg64( u8& val) : value{ val }, bits{ value } {
this->data = value;
}
explicit Reg64(u16& val) : value{ val }, bits{ value } {
this->data = value;
}
explicit Reg64(u32& val) : value{ val }, bits{ value } {
this->data = value;
}
// Constructors by Register Types
template<typename T>
explicit Reg64(Register<T>* reg) {
this->value = static_cast<u64>(reg->data);
this->bits = value;
}
};
std::ostream& operator<<(std::ostream& os, const Reg8& r);
std::ostream& operator<<(std::ostream& os, const Reg16& r);
std::ostream& operator<<(std::ostream& os, const Reg32& r);
std::ostream& operator<<(std::ostream& os, const Reg64& r);
Теперь я пошели превратил их в шаблоны классов, чтобы уменьшить количество дублирования кода.И вот что у меня есть:
Register.h - Более новая версия
template<typename Ty>
struct Register_t {
static constexpr u16 BitCount = sizeof(Ty) * CHAR_BIT;
Ty currentValue;
Ty previousValue;
std::bitset<BitCount> bits;
Register_t() :
currentValue{ 0 },
previousValue{ 0 },
bits{ 0 }{}
template<typename U>
explicit Register_t(U val) :
currentValue{ static_cast<Ty>(val) },
previousValue{ 0 },
bits{ currentValue } {}
template<typename U>
explicit Register_t(Register_t<U>& r) {
this->currentValue = static_cast<Ty>(r->currentValue);
this->bits = r->bits;
}
};
template<typename Ty>
struct Register : public Register_t<Ty> {
Register() = default;
explicit Register(Ty val) : Register_t<Ty>( val ) {}
// Reg8
template<typename U>
Register( u16 val, u8 idx) {
assert(idx == 0 || idx == 1);
getByteFrom(val, idx, currentValue);
this->bits = this->currentValue;
}
Register(u32 val, u8 idx) {
assert(idx <= 0 && idx >= 3);
getByteFrom(val, idx, this->currentValue);
this->bits = this->currentValue;
}
Register(u64 val, u8 idx) {
assert(idx <= 0 && idx <= 7);
getByteFrom(val, idx, this->currentValue);
this->bits = this->currentValue;
}
// Reg16
Register(u32 val, u8 idx) {
assert(idx == 0 || idx == 1);
getWordFrom(val, idx, this->currentValue);
this->bits = this->currentValue;
}
Register(u64 val, u8 idx) {
assert(idx <= 0 && idx <= 3);
getWordFrom(val, idx, this->currentValue);
this->bits = this->currentValue;
}
// Reg32
Register(u64 val, u8 idx) {
assert(idx == 0 || idx == 1);
getDWordFrom(val, idx, this->currentValue);
this->bits = this->currentValue;
}
};
using Reg8 = Register<u8>;
using Reg16 = Register<u16>;
using Reg32 = Register<u32>;
using Reg64 = Register<u64>;
Теперь, когда дело доходит до конструкторов,примет тип std::uintx_t
, а также значение индекса.Например, некоторые объявления конструктора соответствуют:
В исходной версии Reg8
имеет Reg8(u32 val, u8 idx)
и Reg16
имеет Reg16(u32 val, u8 idx)
.И если вы посмотрите поближе, Reg8(...)
утверждает, что idx <= 0 && idx >= 3
, в то время как Reg16(...)
утверждает, что idx == 0 || idx == 1
.
Однако, когда я пытаюсь шаблонировать эти классы и переносить их через конструкторы, они теперь становятся неоднозначными.Я не знаю, как определить, какое утверждение использовать, чтобы различать его как Reg8
, Reg16
, Reg32
и т.д ...