c++ - 将一组类转换为类模板并避免构造函数歧义

标签 c++ templates constructor c++17 disambiguation

我会尽量让这个问题尽可能简短,但有大量代码可以展示,以便人们理解我正在努力实现的目标以及如何解决我当前的问题。

这是我的原始类声明及其所有构造函数:

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 的构造函数类型以及索引值。一些构造函数声明匹配,例如:

原版Reg8Reg8(u32 val, u8 idx)Reg16Reg16(u32 val, u8 idx) .如果你仔细观察 Reg8(...)断言 idx <= 0 && idx >= 3同时Reg16(...)断言 idx == 0 || idx == 1 .

但是,当我尝试对这些类进行模板化并移植构造函数时,它们现在变得模棱两可。我不知道如何确定使用哪个断言来区分它是 Reg8 , Reg16 , Reg32等等……

最佳答案

对我来说,您类的一切似乎都归结为使用 sizeofnumeric_limits::max您类型的未签名版本。

我已经为您写下了我认为该类(class)的外观的粗略草稿:

template <typename T>
struct Register {
    T data;
    T value;
    bitset<sizeof(T) * CHAR_BIT> bits;

    Register() : data(), value() {}

    template <typename P>
    explicit Register(const P val) : data(static_cast<T>(val)), value(data), bits(data) {}

    template <typename P>
    Register(const P val, const unsigned char idx) : data(static_cast<T>((val >> std::size(bits) * idx) & numeric_limits<make_unsigned_t<T>>::max())), value(data), bits(data) {
        assert(idx == '\0' || idx < sizeof(P) / sizeof(T));
    }

    template <typename P>
    Register(const Register<P>& reg) : data(static_cast<T>(reg.data)), value(data), bits(data) {}
};

template <typename T>
ostream& operator<<(ostream& os, const Register<T>& r) {
  os << "Reg" << size(r.bits) << '(' << r.data << ")\nhex: 0x" << uppercase << setfill('0') << setw(sizeof(T) * 2) << hex << r.data << dec << "\nbin: ";

  for(std::size_t i = 0; i < size(r.bits); ++i) {
    cout.put('0' + r.bits[i]);
  }
  return os << endl << endl;
}

template <>
ostream& operator<<<unsigned char>(ostream& os, const Register<unsigned char>& r) {
  os << "Reg" << size(r.bits) << '(' << static_cast<int>(r.data) << ")\nhex: 0x" << uppercase << setfill('0') << setw(sizeof(unsigned char) * 2) << hex << static_cast<int>(r.data) << dec << "\nbin: ";

  for(std::size_t i = 0; i < size(r.bits); ++i) {
    cout.put('0' + r.bits[i]);
  }
  return os << endl << endl;
}

关于c++ - 将一组类转换为类模板并避免构造函数歧义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56126147/

相关文章:

c++ - c++ 11线程的段错误(核心转储)

c++ - 如何从构造函数捕获异常而不处理整个函数?

c++ - 在 C++ 中调用父类的构造函数之前在类中初始化变量

java - 构造函数没有任何返回类型,但是对象是如何创建的呢?

c++ - 如何在多个内核中使用 Eigen::Tensor::convolve?

c++ - MFC在当前目录创建ini文件

python - 如何在 Jinja 模板中调用 Python 函数并使用函数值返回的字典?

c++ - 基类中的私有(private)静态成员

c++ - 模板特化适用于 g++ 但不适用于 Visual C++

c++ - 有关如何使 Z3 更快地评估简单约束的建议