用户定义类模板的赋值运算符有麻烦

时间:2019-06-11 19:52:28

标签: c++ templates c++17 template-specialization assignment-operator

#include <iostream>
#include "Register.h"

int main() {
    // Basic constructors
    Reg8  r8{ 0xC4 };
    Reg16 r16{ 0x1234 };
    Reg32 r32{ 0x89ABCDEF };
    Reg64 r64{ 0xABBA04200240ABBA };

    // I can do this with similar types:
    Reg8  r8b  = r8;  // okay
    Reg16 r16b = r16; // okay
    Reg32 r32b = r32; // okay
    Reg64 r64b = r64; // okay

    Reg8  r8c;
    r8c  = r8;  // okay
    Reg16 r16c;
    r16c = r16; // okay
    Reg32 r32c;
    r32c = r32; // okay
    Reg64 r64c;
    r64c = r64; // okay

    // Attempting with different Register Types.
    // Now Fixed by doing the following:
    // Reg16 r16d = r8; // Not okay - need to static_cast it.
    Reg16 r16d = static_cast<Reg16>(r8); // okay

    // What I would like to do:
    Reg16 r16e;
    r16e = r32; // not okay:

    // NOTE: You can see some of my attempts of overloading
    // specializing the operator=() below the class section.

    return EXIT_SUCCESS;
}

注册。h

#pragma once

#include <algorithm>
#include <bitset>
#include <cassert>
#include <climits>
#include <cstdint>
#include <iterator>
#include <iostream>
#include <iomanip>
#include <limits>
#include <map>
#include <string>
#include <type_traits>

namespace vpc {
    using u8  = std::uint8_t;
    using u16 = std::uint16_t;
    using u32 = std::uint32_t;
    using u64 = std::uint64_t;

    template<typename T>
    struct Register;

    using Reg8  = Register<u8>;
    using Reg16 = Register<u16>;
    using Reg32 = Register<u32>;
    using Reg64 = Register<u64>;

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

        Register() : value{ 0 }, previous_value{ 0 }, bits{ 0 } {}

        template<typename V, std::enable_if_t<(sizeof(V) > sizeof(T))>* = nullptr>
        explicit Register(const V val, const u8 idx = 0) :
            value{ static_cast<T>((val >> std::size(bits) * idx) &
                  std::numeric_limits<std::make_unsigned_t<T>>::max()) },
            previous_value{ 0 },
            bits{ value }
        {
            constexpr u16 sizeT = sizeof(T);
            constexpr u16 sizeP = sizeof(V);
            assert((idx >= 0) && (idx <= ((sizeP / sizeT) - 1)) );
        }

        template<typename V, std::enable_if_t<(sizeof(V) < sizeof(T))>* = nullptr>
        explicit Register(const V val, const u8 idx = 0) :
            value{ static_cast<T>((static_cast<T>(val) << sizeof(V)*CHAR_BIT*idx) &
                  std::numeric_limits<std::make_unsigned_t<T>>::max()) },
            previous_value{ 0 },
            bits{ value }
        {
            constexpr u16 sizeT = sizeof(T);
            constexpr u16 sizeP = sizeof(V);
            assert((idx >= 0) && (idx <= ((sizeT / sizeP) - 1)) );
        }

        template<typename V, std::enable_if_t<(sizeof(V) == sizeof(T))>* = nullptr>
        explicit Register(const V val, const u8 idx = 0) :
            value{ static_cast<T>( val ) }, previous_value{ 0 }, bits{ value }
        {}

        // the explicit on the copy constructor was the culprit
        template<typename V>
        /*explicit*/ Register(const Register<V>& reg, const u8 idx = 0) : Register(reg.value, idx) {}               

        Register& operator=(const Register& obj) {
            this->value = obj.value;
            this->previous_value = obj.previous_value;
            this->bits = obj.bits;
            return *this;
        }
    };      

} // namespace vpc

这是重载的一些尝试-专用于operator=(),这些都在我的类的声明中。

Reg8& operator=(const Reg16& rhs) {
    Reg8 temp{ rhs };
    this->value = temp.value;
    this->previous_value = temp.previous_value;
    this->bits = temp.bits;
    return *this;
}

Reg8& operator=(const Reg32& rhs) {
    Reg8 temp{ rhs };
    this->value = temp.value;
    this->previous_value = temp.previous_value;
    this->bits = temp.bits;
    return *this;
}

Reg8& operator=(const Reg64& rhs) {
    Reg8 temp{ rhs };
    this->value = temp.value;
    this->previous_value = temp.previous_value;
    this->bits = temp.bits;
    return *this;
}

Reg16& operator=(const Reg8& rhs) {
    Reg16 temp{ rhs };
    this->value = temp.value;
    this->previous_value = temp.previous_value;
    this->bits = temp.bits;
    return *this;
}


Reg16& operator=(const Reg32& rhs) {
    Reg16 temp{ rhs };
    this->value = temp.value;
    this->previous_value = temp.previous_value;
    this->bits = temp.bits;
    return *this;
}

Reg16& operator=(const Reg64& rhs) {
    Reg16 temp{ rhs };
    this->value = temp.value;
    this->previous_value = temp.previous_value;
    this->bits = temp.bits;
    return *this;
}

我相信应该有一种方法可以做到这一点,但是我不确定如何做到,如果我在正确处理这些重载的正确道路上,我不知道正确的语法和Visual Studio给我这个编译器错误:

1>------ Build started: Project: TestRegister, Configuration: Debug x64 ------
1>main.cpp
1>c:\...\register.h(109): error C2556: 'vpc::Reg16 &vpc::Register<vpc::u8>::operator =(const vpc::Reg8 &)': overloaded function differs only by return type from 'vpc::Register<vpc::u8> &vpc::Register<vpc::u8>::operator =(const vpc::Register<vpc::u8> &)'
1>c:\...\register.h(78): note: see declaration of 'vpc::Register<vpc::u8>::operator ='
1>c:\...\main.cpp(23): note: see reference to class template instantiation 'vpc::Register<vpc::u8>' being compiled
1>c:\...\register.h(109): error C2371: 'vpc::Register<vpc::u8>::operator =': redefinition; different basic types
1>c:\...\register.h(78): note: see declaration of 'vpc::Register<vpc::u8>::operator ='
1>c:\...\register.h(85): error C2556: 'vpc::Reg8 &vpc::Register<vpc::u16>::operator =(const vpc::Reg16 &)': overloaded function differs only by return type from 'vpc::Register<vpc::u16> &vpc::Register<vpc::u16>::operator =(const vpc::Register<vpc::u16> &)'
1>c:\...\register.h(78): note: see declaration of 'vpc::Register<vpc::u16>::operator ='
1>c:\...\register.h(110): note: see reference to class template instantiation 'vpc::Register<vpc::u16>' being compiled
1>c:\...\register.h(85): error C2371: 'vpc::Register<vpc::u16>::operator =': redefinition; different basic types
1>c:\...\register.h(78): note: see declaration of 'vpc::Register<vpc::u16>::operator ='
1>c:\...\register.h(86): error C2079: 'vpc::Register<vpc::u16>::temp' uses undefined struct 'vpc::Register<vpc::u8>'
1>c:\...\register.h(87): error C2059: syntax error: 'this'
1>c:\...\register.h(87): error C2238: unexpected token(s) preceding ';'
1>c:\...\register.h(88): error C2059: syntax error: 'this'
1>c:\...\register.h(88): error C2238: unexpected token(s) preceding ';'
1>c:\...\register.h(89): error C2059: syntax error: 'this'
1>c:\...\register.h(89): error C2238: unexpected token(s) preceding ';'
1>c:\...\register.h(90): error C2059: syntax error: 'return'
1>c:\...\register.h(90): error C2238: unexpected token(s) preceding ';'
1>c:\...\register.h(93): error C2143: syntax error: missing ';' before ''symbol''
1>c:\...\register.h(111): error C2059: syntax error: 'this'
1>c:\...\register.h(111): error C2238: unexpected token(s) preceding ';'
1>c:\...\register.h(112): error C2059: syntax error: 'this'
1>c:\...\register.h(112): error C2238: unexpected token(s) preceding ';'
1>c:\...\register.h(113): error C2059: syntax error: 'this'
1>c:\...\register.h(113): error C2238: unexpected token(s) preceding ';'
1>c:\...\register.h(114): error C2059: syntax error: 'return'
1>c:\...\register.h(114): error C2238: unexpected token(s) preceding ';'
1>c:\...\register.h(117): error C2143: syntax error: missing ';' before ''symbol''
1>c:\...\main.cpp(29): error C2679: binary '=': no operator found which takes a right-hand operand of type 'vpc::Reg8' (or there is no acceptable conversion)
1>c:\...\register.h(78): note: could be 'vpc::Register<vpc::u16> &vpc::Register<vpc::u16>::operator =(const vpc::Register<vpc::u16> &)'
1>c:\...\main.cpp(29): note: while trying to match the argument list '(vpc::Reg16, vpc::Reg8)'
1>c:\...\register.h(101): error C2556: 'vpc::Reg8 &vpc::Register<vpc::u64>::operator =(const vpc::Reg64 &)': overloaded function differs only by return type from 'vpc::Register<vpc::u64> &vpc::Register<vpc::u64>::operator =(const vpc::Register<vpc::u64> &)'
1>c:\...\register.h(78): note: see declaration of 'vpc::Register<vpc::u64>::operator ='
1>c:\...\main.cpp(141): note: see reference to class template instantiation 'vpc::Register<vpc::u64>' being compiled
1>c:\...\register.h(101): error C2371: 'vpc::Register<vpc::u64>::operator =': redefinition; different basic types
1>c:\...\register.h(78): note: see declaration of 'vpc::Register<vpc::u64>::operator ='
1>c:\...\register.h(103): error C2059: syntax error: 'this'
1>c:\...\register.h(103): error C2238: unexpected token(s) preceding ';'
1>c:\...\register.h(104): error C2059: syntax error: 'this'
1>c:\...\register.h(104): error C2238: unexpected token(s) preceding ';'
1>c:\...\register.h(105): error C2059: syntax error: 'this'
1>c:\...\register.h(105): error C2238: unexpected token(s) preceding ';'
1>c:\...\register.h(106): error C2059: syntax error: 'return'
1>c:\...\register.h(106): error C2238: unexpected token(s) preceding ';'
1>c:\...\register.h(109): error C2143: syntax error: missing ';' before ''symbol''
1>c:\...\register.h(93): error C2556: 'vpc::Reg8 &vpc::Register<vpc::u32>::operator =(const vpc::Reg32 &)': overloaded function differs only by return type from 'vpc::Register<vpc::u32> &vpc::Register<vpc::u32>::operator =(const vpc::Register<vpc::u32> &)'
1>c:\...\register.h(78): note: see declaration of 'vpc::Register<vpc::u32>::operator ='
1>c:\...\main.cpp(142): note: see reference to class template instantiation 'vpc::Register<vpc::u32>' being compiled
1>c:\...\register.h(93): error C2371: 'vpc::Register<vpc::u32>::operator =': redefinition; different basic types
1>c:\...\register.h(78): note: see declaration of 'vpc::Register<vpc::u32>::operator ='
1>c:\...\register.h(95): error C2059: syntax error: 'this'
1>c:\...\register.h(95): error C2238: unexpected token(s) preceding ';'
1>c:\...\register.h(96): error C2059: syntax error: 'this'
1>c:\...\register.h(96): error C2238: unexpected token(s) preceding ';'
1>c:\...\register.h(97): error C2059: syntax error: 'this'
1>c:\...\register.h(97): error C2238: unexpected token(s) preceding ';'
1>c:\...\register.h(98): error C2059: syntax error: 'return'
1>c:\...\register.h(98): error C2238: unexpected token(s) preceding ';'
1>c:\...\register.h(101): error C2143: syntax error: missing ';' before ''symbol''
1>Done building project "TestRegister.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

我尝试了许多其他方式,我搜索了google,在这里搜索了其他问题,但是似乎找不到与我的情况相关的任何东西,除非我忽略了一些东西。我该怎么做才能编译它?

编辑

由于explicit上的Copy Constructor被忽略,复制构造函数和赋值运算符都失败了。这给了我太多的Visual Studio编译器错误。删除该显式关键字即可解决所有问题。上面我的课程中的operator=()就足够了。类部分下的重载或专业化甚至根本不需要。超过3个小时的时间试图解决这个问题...

1 个答案:

答案 0 :(得分:2)

如果我正确理解了您的代码,则简单地将operator=()用于不同的Register<T>类型

    template <typename U>
    Register & operator= (Register<U> const & obj)
     { return *this = Register{obj}; }

但是当你写

    Reg16 r16c = r8; 

您是在打电话给建设者,而不是operator=()

在我看来,您必须删除其中的explicit

    template<typename V>
    explicit Register(const Register<V>& reg, const u8 idx = 0) : Register(reg.value, idx) {}

您还必须更正主operator=(),因为obj是引用,而不是指针;因此您必须使用点运算符,而不是箭头运算符

    Register& operator=(const Register& obj) {
        this->value = obj.value; // not obj->value
        this->previous_value = obj.previous_value; // not obj->previous_value
        this->bits = obj.bits; // not obj->bits
        return *this;
    };

传人:您的主要operator=()是否等于默认的operator=()