使用类模板的用户定义的赋值运算符时遇到问题 [已关闭]

Having trouble with user defined assignment operator for class template [closed]

提问人:Francis Cugler 提问时间:6/12/2019 最后编辑:Francis Cugler 更新时间:6/12/2019 访问量:88

问:


编辑问题以包括所需的行为、特定问题或错误以及重现问题所需的最短代码。这将有助于其他人回答这个问题。

4年前关闭。

#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 ==========

我尝试了很多其他方法,我搜索了谷歌,我在这里搜索了其他问答,但似乎找不到任何与我的情况相关的内容,除非我忽略了什么。我必须做些什么才能编译它?

编辑

复制构造函数和赋值运算符都失败了,因为 上忽略了 。这给了我大量的 Visual Studio 编译器错误。删除那个明确的关键字,解决了所有问题。而我上面的班级就是所需要的。甚至根本不需要类部分下方的重载或专业化。3个多小时试图弄清楚这一点......explicitCopy Constructoroperator=()

C++ C++17 模板专用化 赋值运算符

评论

3赞 Barry 6/12/2019
请看一下什么是最小可重现的例子。这里有很多与您的问题无关的内容。
2赞 HTNW 6/12/2019
同时声明和 “赋值” 不是赋值 — 没有参与 That's a constructor 调用,等效于operator=Reg16 r16c = r8;Reg16 r16c(static_cast<Reg16>(r8));
1赞 jww 6/12/2019
最小、完整和可验证的示例
3赞 Barry 6/12/2019
链接帮助中对“最小”的描述指出“使用尽可能少的代码,但仍会产生相同的问题。这里的问题是数百行代码,并且包含许多不需要演示问题的函数。许多人根本没有被召唤。对于问题的目的来说,许多细节实际上并不重要。同时,现在你删除了问题的实际问题部分,所以甚至不清楚你在问什么。就目前而言,它是“这里有一堆代码,你弄清楚我想要什么。
2赞 Lightness Races in Orbit 6/12/2019
这表明您尚未完成调试,并且尚未处于“ask Stack Overflow”阶段!祝你好运。

答:

2赞 max66 6/12/2019 #1

如果我正确理解您的代码,那么不同类型的代码很简单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) {}

您还必须更正 main,因为它是引用,而不是指针;所以你必须使用点运算符,而不是箭头运算符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=()

评论

0赞 Francis Cugler 6/12/2019
我更新了我的问题,我仍然想保持明确。我必须用它来使赋值构造函数工作。但是我仍然有问题。static_cast<type>(obj)
0赞 max66 6/12/2019
@FrancisCugler - 如果你想维护它,你必须写 .无论如何,你的主要.答案已改进。explicitReg16 r16c = Reg16{r8};operator=()
0赞 Francis Cugler 6/12/2019
是的,我注意到了这一点,并在我的源代码中修复了它。
0赞 max66 6/12/2019
@FrancisCugler - 通过更正,并添加我的模板,在我的平台中编译。operator=()Reg16 r16d; r16d = r8;
1赞 Lightness Races in Orbit 6/12/2019
explicit在复制构造函数上很奇怪。弗朗西斯,你为什么要保留它?