Вот мой код:
Регистрация.h
#include <assert.h>
#include <bitset>
#include <cstdint>
#include <iostream>
#include <iomanip>
#include <iterator>
#include <limits>
#include <numeric>
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 {
T data;
T value;
std::bitset<sizeof(T)* CHAR_BIT> bits;
Register() = default;
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 u8 idx) :
data{ static_cast<T>((val >> std::size(bits) * idx) &
std::numeric_limits<std::make_unsigned<T>>::max()) },
value{ data },
bits{ data }
{
assert(idx >= '\0' && idx < sizeof(T));
}
template<typename P>
Register(const Register<P>& reg) :
data{ static_cast<T>(reg.data) },
value{ data },
bits{ data }
{}
template<typename P>
Register(const Register<P>& reg, const u8 idx) :
data{ static_cast<T>((reg.data >> std::size(bits) * idx) &
std::numeric_limits<std::make_unsigned<T>>::max()) },
value{ data },
bits{ data }
{
assert(idx >= 0 && idx < sizeof(T));
}
};
template<typename T>
std::ostream& operator<<(std::ostream& os, const Register<T>& r) {
return os << "Reg" << std::size(r.bits) << '(' << +r.data << ")\nhex: 0x"
<< std::uppercase << std::setfill('0') << std::setw(sizeof(T) * 2) << std::hex
<< +r.data << std::dec << "\nbin: "
<< r.bits << "\n\n";
}
using Reg8 = Register<u8>;
using Reg16 = Register<u16>;
using Reg32 = Register<u32>;
using Reg64 = Register<u64>;
} // namespace vpc
В моей основной функции, где я использую этот класс, работает конструктор по умолчанию, работает второй конструктор путем передачи как значений, так и переменных. Третий конструктор дает мне ошибку компилятора.
main.cpp
#include "Register.h"
int main() {
using namespace vpc;
u16 val = 0xC97B;
Reg8 r8low( val, 0 ); // should be 7B
Reg8 r8high( val, 1 ); // should be C9
std::cout << r8low << r8high;
return EXIT_SUCCESS;
}
Это ошибка компилятора, которую я получаю от Visual Studio 2017:
1>------ Build started: Project: TestRegister, Configuration: Debug x64 ------
1>main.cpp
1>c:\***\register.h(38): error C2678: binary '&': no operator found which takes a left-hand operand of type 'int' (or there is no acceptable conversion)
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\cstddef(45): note: could be 'std::byte std::operator &(const std::byte,const std::byte) noexcept' [found using argument-dependent lookup]
1>c:\***\register.h(39): note: while trying to match the argument list '(int, _Ty)'
1> with
1> [
1> _Ty=std::make_unsigned<vpc::u8>
1> ]
1>c:\***\main.cpp(15): note: see reference to function template instantiation 'vpc::Register<vpc::u8>::Register<vpc::u16>(const P,const vpc::u8)' being compiled
1> with
1> [
1> P=vpc::u16
1> ]
1>c:\***\main.cpp(15): note: see reference to function template instantiation 'vpc::Register<vpc::u8>::Register<vpc::u16>(const P,const vpc::u8)' being compiled
1> with
1> [
1> P=vpc::u16
1> ]
1>Done building project "TestRegister.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Я понимаю, что такое ошибка компилятора; но я не знаю, что именно вызывает это. Это исходит от std::size или std::numeric_limits<...>() ? Там написано левая сторона, так что я предполагаю std::size()...
Я не знаю, как это решить. Что я могу сделать, чтобы иметь возможность скомпилировать это? Я почти уверен, что если этот конструктор вызывает эту ошибку, то мой последний конструктор, вероятно, вызовет ту же или аналогичную ошибку.





Измените std::make_unsigned<T> на std::make_unsigned_t<T> (или typename std::make_unsigned<T>::type до C++14); Вам нужен соответствующий беззнаковый тип, а не сам std::make_unsigned. то есть
template<typename P>
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 }
{
assert(idx >= '\0' && idx < sizeof(T));
}
У меня есть еще один вопрос относительно того же кода выше, однако мне не хочется писать полностью новый вопрос, и я не хочу добавлять к этому выше, потому что это совершенно другая и неактуальная проблема. Я могу попытаться описать свои намерения в комментариях здесь, хотя это относится к тому же конструктору... это связано с расчетами для моего assert(...)
Мои Reg8, Reg16, Reg32 и Reg64 содержат 1,2,4 и 8 байт и 8, 16, 32 и 64 бита в bitset. Это относится к случаям, когда я создаю регистр меньшего размера либо из значения большего размера, либо из регистра большего размера со значением индекса. Если я строю Reg8 из u16 или Reg16, диапазон индексов равен [0,1], Reg8 из u32 или Reg32 диапазон равен [0,3], Reg8 из u64 или Reg64 диапазон равен [0,7], Reg16 из u32 или Reg32 диапазон равен [0,1], Reg16 из u64 или Reg64 диапазон [0,4] и Reg32 из u64 или Reg64 диапазон [0,1]. Верен ли мой расчет?
Хорошо, нет проблем, подумал я, хотя могу спросить... Я могу провести тщательное модульное тестирование, чтобы увидеть, работают ли мои утверждения или нет... и увидеть, где они терпят неудачу в каждом случае.
Кажется, я понял это. Нижняя граница всегда 0 достаточно проста. Верхняя граница зависит как от sizeof(T) типа, так и от sizeof(P) типа, из которого он строится. Таким образом, уравнение для верхней границы выглядит так: (sizeof(P) / sizeof(T)) - 1;
Всегда хорошо иметь второй набор или пару глаз! Любые глаза тоже будут работать, они даже могут быть вариантами в этом отношении.