代码之家  ›  专栏  ›  技术社区  ›  Francis Cugler

将类模板转换为SFINAE和构造函数委托,现在出现编译器错误

  •  0
  • Francis Cugler  · 技术社区  · 6 年前

    最初我有一个类模板声明:

    寄存器.h -- 原件

    #pragma once
    
    #include <assert.h>
    #include <bitset>
    #include <cstdint>
    #include <limits>
    #include <type_traits>
    
    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 {
        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) {}
    };
    
    using Reg8  = Register<u8>;
    using Reg16 = Register<u16>;
    using Reg32 = Register<u32>;
    using Reg64 = Register<u64>;
    

    我可以这样做:

    void someFunc() {
        // by const value
        Reg64 r64{ 0x0123456789ABCDEF };
        Reg32 r32{ 0x89ABCDEF };
        Reg16 r16{ 0xCDEF };
        Reg8  r8{ 0xEf };
    
        // unsigned type
        u8  byte  = 8;
        u16 word  = 16;
        u32 dword = 32;
        u64 qword = 64;
    
        Reg8 r8a{byte};
        Reg16 r16a{word};
        Reg32 r32a{dword};
        Reg64 r64a{qword};
    
        // Or from any other Register<T> type.
    }
    

    现在我将类模板的构造函数转换为SFINAE,它们现在如下所示:

    #pragma once
    
    #include <assert.h>
    #include <bitset>
    #include <cstdint>
    #include <limits>
    #include <type_traits>
    
    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 {
        T data;
        T value;
        std::bitset<sizeof(T)* CHAR_BIT> bits;
    
        Register() : data{ 0 }, value{ 0 }, bits{ 0 } {}
    
        template<typename P, std::enable_if_t<(sizeof(P) > sizeof(T))>* = nullptr>
        Register(const P val, const u8 idx) :
            data{ static_cast<T>((val >> std::size(bits) * idx) &
                  std::numeric_limits<std::make_unsigned_t<T>>::max()) },
            value{ data },
            bits{ data }
        {
    
            constexpr u16 sizeT = sizeof(T);
            constexpr u16 sizeP = sizeof(P);
            assert((idx >= 0) && (idx <= ((sizeP / sizeT) - 1)) );
        }
    
    
        template<typename P, std::enable_if_t<(sizeof(P) < sizeof(T))>* = nullptr>
        Register(const P val, const u8 idx) :
            data{ /*static_cast<T>((val >> std::size(bits) * idx) &
                  std::numeric_limits<std::make_unsigned_t<T>>::max()) },*/
                static_cast<T>(val)
                },
            value{ data },
            bits{ data }
        {
            constexpr u16 sizeT = sizeof(T);
            constexpr u16 sizeP = sizeof(P);
            assert((idx >= 0) && (idx <= ((sizeT / sizeP) - 1)) );
        }
    
    
        template<typename P, std::enable_if_t<(sizeof(P) == sizeof(T))>* = nullptr>
        Register(const P val, const u8 idx = 0) :
            data{ static_cast<T>( val ) }, value{ data }, bits{ data }
        {}
    
        template<typename P>
        Register(const Register<P>& reg, const u8 idx = 0) : Register(reg.data, idx) {}
    
    };
    
    using Reg8  = Register<u8>;
    using Reg16 = Register<u16>;
    using Reg32 = Register<u32>;
    using Reg64 = Register<u64>;
    

    现在,当我尝试像以前那样构造它们时,我没有得到编译器错误:注意*,这些编译器错误不是来自伪函数 someFunc 上面,这是从我的 testing 以前编译和运行时没有错误的函数。如果需要的话,我可以在这些错误下面发布这些函数;只要提出请求,我就会添加它们。

    1>------ Build started: Project: TestRegister, Configuration: Debug x64 ------
    1>main.cpp
    1>c:\***\main.cpp(54): error C2440: 'initializing': cannot convert from 'initializer list' to 'vpc::Register<vpc::u16>'
    1>c:\***\main.cpp(54): note: No constructor could take the source type, or constructor overload resolution was ambiguous
    1>c:\***\main.cpp(55): error C2440: 'initializing': cannot convert from 'initializer list' to 'vpc::Register<vpc::u8>'
    1>c:\***\main.cpp(55): note: No constructor could take the source type, or constructor overload resolution was ambiguous
    1>c:\***\main.cpp(195): error C2665: 'vpc::Register<vpc::u8>::Register': none of the 3 overloads could convert all the argument types
    1>c:\***\register.h(73): note: could be 'vpc::Register<vpc::u8>::Register(vpc::Register<vpc::u8> &&)'
    1>c:\***\register.h(73): note: or       'vpc::Register<vpc::u8>::Register(const vpc::Register<vpc::u8> &)'
    1>c:\***\register.h(34): note: or       'vpc::Register<vpc::u8>::Register(void)'
    1>c:\***\main.cpp(195): note: while trying to match the argument list '(u16)'
    1>c:\***\main.cpp(196): error C2665: 'vpc::Register<vpc::u8>::Register': none of the 3 overloads could convert all the argument types
    1>c:\***\register.h(73): note: could be 'vpc::Register<vpc::u8>::Register(vpc::Register<vpc::u8> &&)'
    1>c:\***\register.h(73): note: or       'vpc::Register<vpc::u8>::Register(const vpc::Register<vpc::u8> &)'
    1>c:\***\register.h(34): note: or       'vpc::Register<vpc::u8>::Register(void)'
    1>c:\***\main.cpp(196): note: while trying to match the argument list '(u32)'
    1>c:\***\main.cpp(197): error C2665: 'vpc::Register<vpc::u8>::Register': none of the 3 overloads could convert all the argument types
    1>c:\***\register.h(73): note: could be 'vpc::Register<vpc::u8>::Register(vpc::Register<vpc::u8> &&)'
    1>c:\***\register.h(73): note: or       'vpc::Register<vpc::u8>::Register(const vpc::Register<vpc::u8> &)'
    1>c:\***\register.h(34): note: or       'vpc::Register<vpc::u8>::Register(void)'
    1>c:\***\main.cpp(197): note: while trying to match the argument list '(u64)'
    1>c:\***\main.cpp(238): error C2665: 'vpc::Register<vpc::u16>::Register': none of the 3 overloads could convert all the argument types
    1>c:\***\register.h(73): note: could be 'vpc::Register<vpc::u16>::Register(vpc::Register<vpc::u16> &&)'
    1>c:\***\register.h(73): note: or       'vpc::Register<vpc::u16>::Register(const vpc::Register<vpc::u16> &)'
    1>c:\***\register.h(34): note: or       'vpc::Register<vpc::u16>::Register(void)'
    1>c:\***\main.cpp(238): note: while trying to match the argument list '(u8)'
    1>c:\***\main.cpp(239): error C2665: 'vpc::Register<vpc::u16>::Register': none of the 3 overloads could convert all the argument types
    1>c:\***\register.h(73): note: could be 'vpc::Register<vpc::u16>::Register(vpc::Register<vpc::u16> &&)'
    1>c:\***\register.h(73): note: or       'vpc::Register<vpc::u16>::Register(const vpc::Register<vpc::u16> &)'
    1>c:\***\register.h(34): note: or       'vpc::Register<vpc::u16>::Register(void)'
    1>c:\***\main.cpp(239): note: while trying to match the argument list '(u8)'
    1>c:\***\main.cpp(241): error C2665: 'vpc::Register<vpc::u16>::Register': none of the 3 overloads could convert all the argument types
    1>c:\***\register.h(73): note: could be 'vpc::Register<vpc::u16>::Register(vpc::Register<vpc::u16> &&)'
    1>c:\***\register.h(73): note: or       'vpc::Register<vpc::u16>::Register(const vpc::Register<vpc::u16> &)'
    1>c:\***\register.h(34): note: or       'vpc::Register<vpc::u16>::Register(void)'
    1>c:\***\main.cpp(241): note: while trying to match the argument list '(u32)'
    1>c:\***\main.cpp(242): error C2665: 'vpc::Register<vpc::u16>::Register': none of the 3 overloads could convert all the argument types
    1>c:\***\register.h(73): note: could be 'vpc::Register<vpc::u16>::Register(vpc::Register<vpc::u16> &&)'
    1>c:\***\register.h(73): note: or       'vpc::Register<vpc::u16>::Register(const vpc::Register<vpc::u16> &)'
    1>c:\***\register.h(34): note: or       'vpc::Register<vpc::u16>::Register(void)'
    1>c:\***\main.cpp(242): note: while trying to match the argument list '(u64)'
    1>c:\***\main.cpp(267): error C2665: 'vpc::Register<vpc::u32>::Register': none of the 3 overloads could convert all the argument types
    1>c:\***\register.h(73): note: could be 'vpc::Register<vpc::u32>::Register(vpc::Register<vpc::u32> &&)'
    1>c:\***\register.h(73): note: or       'vpc::Register<vpc::u32>::Register(const vpc::Register<vpc::u32> &)'
    1>c:\***\register.h(34): note: or       'vpc::Register<vpc::u32>::Register(void)'
    1>c:\***\main.cpp(267): note: while trying to match the argument list '(u8)'
    1>c:\***\main.cpp(268): error C2665: 'vpc::Register<vpc::u32>::Register': none of the 3 overloads could convert all the argument types
    1>c:\***\register.h(73): note: could be 'vpc::Register<vpc::u32>::Register(vpc::Register<vpc::u32> &&)'
    1>c:\***\register.h(73): note: or       'vpc::Register<vpc::u32>::Register(const vpc::Register<vpc::u32> &)'
    1>c:\***\register.h(34): note: or       'vpc::Register<vpc::u32>::Register(void)'
    1>c:\***\main.cpp(268): note: while trying to match the argument list '(u8)'
    1>c:\***\main.cpp(269): error C2665: 'vpc::Register<vpc::u32>::Register': none of the 3 overloads could convert all the argument types
    1>c:\***\register.h(73): note: could be 'vpc::Register<vpc::u32>::Register(vpc::Register<vpc::u32> &&)'
    1>c:\***\register.h(73): note: or       'vpc::Register<vpc::u32>::Register(const vpc::Register<vpc::u32> &)'
    1>c:\***\register.h(34): note: or       'vpc::Register<vpc::u32>::Register(void)'
    1>c:\***\main.cpp(269): note: while trying to match the argument list '(u16)'
    1>c:\***\main.cpp(271): error C2665: 'vpc::Register<vpc::u32>::Register': none of the 3 overloads could convert all the argument types
    1>c:\***\register.h(73): note: could be 'vpc::Register<vpc::u32>::Register(vpc::Register<vpc::u32> &&)'
    1>c:\***\register.h(73): note: or       'vpc::Register<vpc::u32>::Register(const vpc::Register<vpc::u32> &)'
    1>c:\***\register.h(34): note: or       'vpc::Register<vpc::u32>::Register(void)'
    1>c:\***\main.cpp(271): note: while trying to match the argument list '(u64)'
    1>c:\***\main.cpp(285): error C2665: 'vpc::Register<vpc::u64>::Register': none of the 3 overloads could convert all the argument types
    1>c:\***\register.h(73): note: could be 'vpc::Register<vpc::u64>::Register(vpc::Register<vpc::u64> &&)'
    1>c:\***\register.h(73): note: or       'vpc::Register<vpc::u64>::Register(const vpc::Register<vpc::u64> &)'
    1>c:\***\register.h(34): note: or       'vpc::Register<vpc::u64>::Register(void)'
    1>c:\***\main.cpp(285): note: while trying to match the argument list '(u8)'
    1>c:\***\main.cpp(286): error C2665: 'vpc::Register<vpc::u64>::Register': none of the 3 overloads could convert all the argument types
    1>c:\***\register.h(73): note: could be 'vpc::Register<vpc::u64>::Register(vpc::Register<vpc::u64> &&)'
    1>c:\***\register.h(73): note: or       'vpc::Register<vpc::u64>::Register(const vpc::Register<vpc::u64> &)'
    1>c:\***\register.h(34): note: or       'vpc::Register<vpc::u64>::Register(void)'
    1>c:\***\main.cpp(286): note: while trying to match the argument list '(u8)'
    1>c:\***\main.cpp(287): error C2665: 'vpc::Register<vpc::u64>::Register': none of the 3 overloads could convert all the argument types
    1>c:\***\register.h(73): note: could be 'vpc::Register<vpc::u64>::Register(vpc::Register<vpc::u64> &&)'
    1>c:\***\register.h(73): note: or       'vpc::Register<vpc::u64>::Register(const vpc::Register<vpc::u64> &)'
    1>c:\***\register.h(34): note: or       'vpc::Register<vpc::u64>::Register(void)'
    1>c:\***\main.cpp(287): note: while trying to match the argument list '(u16)'
    1>c:\***\main.cpp(288): error C2665: 'vpc::Register<vpc::u64>::Register': none of the 3 overloads could convert all the argument types
    1>c:\***\register.h(73): note: could be 'vpc::Register<vpc::u64>::Register(vpc::Register<vpc::u64> &&)'
    1>c:\***\register.h(73): note: or       'vpc::Register<vpc::u64>::Register(const vpc::Register<vpc::u64> &)'
    1>c:\***\register.h(34): note: or       'vpc::Register<vpc::u64>::Register(void)'
    1>c:\users\skilz99\source\repos\testregister\testregister\main.cpp(288): note: while trying to match the argument list '(u32)'
    1>Done building project "TestRegister.vcxproj" -- FAILED.
    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
    

    所以现在我得到了一些重复的类型错误,首先它不能从初始值设定项列表转换,然后我得到了模棱两可的构造函数调用。。。

    1 回复  |  直到 6 年前
        1
  •  2
  •   aschepler    6 年前

    您从两个构造函数模板中删除了默认参数。

    template<typename P, std::enable_if_t<(sizeof(P) > sizeof(T))>* = nullptr>
        Register(const P val, const u8 idx) : // ...
    
    template<typename P, std::enable_if_t<(sizeof(P) < sizeof(T))>* = nullptr>
        Register(const P val, const u8 idx) : // ...
    

    应该是:

    template<typename P, std::enable_if_t<(sizeof(P) > sizeof(T))>* = nullptr>
        Register(const P val, const u8 idx = 0) : // ...
    
    template<typename P, std::enable_if_t<(sizeof(P) < sizeof(T))>* = nullptr>
        Register(const P val, const u8 idx = 0) : // ...
    

    所以编译器无法转换为 Register<T> 从一个 P 不同的 sizeof ,因为它只看到一个参数,而没有考虑其他两个构造函数模板。