在使用类模板时,是否可以通过推断其类型来指定特定大小?这是一个伪代码示例,用来表示我要询问的内容。
#include <bitset>
#include <cstdint>
namespace xxx {
#define BYTE 8
#define WORD 16
#define DWORD 32
#define QWORD 64
typedef std::uint8_t u8;
typedef std::uint16_t u16;
typedef std::uint32_t u32;
typedef std::uint64_t u64;
template<typename Type, u16 BitCount>
struct Register {
};
}
我不知道我可以使用部分专业化还是完全专业化,我也不知道该怎么做。我想做的是以下事情:
- 如果
Type
==u8
,则BitCount
自动==BYTE
或8
- 如果
Type
==u16
,则BitCount
自动==WORD
或16
- 如果
Type
==u32
,则BitCount
自动==DWORD
或32
- 如果
Type
==u64
,则BitCount
自动==QWORD
或64
这样做的原因是,当涉及到上面的类及其成员时,我尚未显示但在此处将要显示的是,它的成员之一是std::bitset
template<typename Type, u16 BitCount>
struct Register {
Type value;
std::bitset<BitCount>
};
是的,我知道我可以这样实例化它们:
void someFunc() {
Register<u8, 8> r8;
Register<u16, 16> r16;
}
但是我希望能够专门化它们,这样您就不必传入任何参数类型,我希望可以通过传入的参数类型来推论它们,或者如果只是传递一个类型,那么大小部分是自动的。这是首选
void someFunc() {
Register<u8> r8;
}
// the class would automatically use `8` for its `std::bitset<8>` member.
始终存在其基础类型和位大小的一对一对应关系。
这种实例化无效:
Register<u32, 64> reg; // invalid type u32 can only be 32...
是否有通过专门化,继承,多态等方法来做到这一点?
答案 0 :(得分:5)
您可以只使用usings:
using u8Register = Register<u8, BYTE>;
using u16Register = Register<u16, WORD>;
using u32Register = Register<u32, DWORD>;
using u64Register = Register<u64, QWORD>;
或者,如果这些类型与其字节大小一一对应,则可以使用sizeof
:
#include <limits.h>
template<typename Type, u16 BitCount = sizeof(Type) * CHAR_BIT>
struct Register {
Type value;
std::bitset<BitCount>
};
或者您可以从Register
继承来专门化。
答案 1 :(得分:4)
听起来您实际上并不需要第二个模板参数。您只需要一个模板参数,并直接从中确定位数:
template <typename Type>
struct Register {
static constexpr auto Bits = sizeof(Type) * CHAR_BIT;
// ...
};
或者,如果您想对此逻辑进行某种概括:
template <typename> struct BitCount;
template <> struct BitCount<uint8_t> : integral_constant<size_t, 8> {};
template <> struct BitCount<uint16_t> : integral_constant<size_t, 16> {};
// ...
template <typename Type>
struct Register {
static constexpr auto Bits = BitCount<T>::value;
// ...
};
答案 2 :(得分:-1)
解决我的问题;他们俩对此都给出了类似的答案,但我认为Barry的表达方式更具表现力,因此我必须为他的回答功劳。
现在,对于Sombrero,他的确为我提供了using Reg# = Register<T>
的帮助,因此我不必通过传递它们的类型参数来调用这些模板。
基本上可以归结为:
static constexpr auto Bits = sizeof(Type) * CHAR_BIT;
感谢您为我提供的帮助。
使用来自用户Barry
和SombreroChicken
的反馈,我能够做到这一点:
main.cpp
#include <iostream>
#include "Register.h"
int main() {
using namespace vpc;
u8 valA = 8;
u16 valB = 16;
u32 valC = 32;
u64 valD = 64;
Reg8 r8A(valA);
Reg8 r8B(valB);
Reg8 r8C(valC);
Reg8 r8D(valD);
Reg16 r16A(valA);
Reg16 r16B(valB);
Reg16 r16C(valC);
Reg16 r16D(valD);
Reg32 r32A(valA);
Reg32 r32B(valB);
Reg32 r32C(valC);
Reg32 r32D(valD);
Reg64 r64A(valA);
Reg64 r64B(valB);
Reg64 r64C(valC);
Reg64 r64D(valD);
std::cout << r8A << r8B << r8C << r8D;
std::cout << r16A << r16B << r16C << r16D;
std::cout << r32A << r32B << r32C << r32D;
std::cout << r64A << r64B << r64C << r64D;
return EXIT_SUCCESS;
}
输出
Reg8(8)
hex: 0x08
bin: 00001000
Reg8(16)
hex: 0x10
bin: 00010000
Reg8(32)
hex: 0x20
bin: 00100000
Reg8(64)
hex: 0x40
bin: 01000000
Reg16(8)
hex: 0x0008
bin: 0000000000001000
Reg16(16)
hex: 0x0010
bin: 0000000000010000
Reg16(32)
hex: 0x0020
bin: 0000000000100000
Reg16(64)
hex: 0x0040
bin: 0000000001000000
Reg32(8)
hex: 0x00000008
bin: 00000000000000000000000000001000
Reg32(16)
hex: 0x00000010
bin: 00000000000000000000000000010000
Reg32(32)
hex: 0x00000020
bin: 00000000000000000000000000100000
Reg32(64)
hex: 0x00000040
bin: 00000000000000000000000001000000
Reg64(8)
hex: 0x0000000000000008
bin: 0000000000000000000000000000000000000000000000000000000000001000
Reg64(16)
hex: 0x0000000000000010
bin: 0000000000000000000000000000000000000000000000000000000000010000
Reg64(32)
hex: 0x0000000000000020
bin: 0000000000000000000000000000000000000000000000000000000000100000
Reg64(64)
hex: 0x0000000000000040
bin: 0000000000000000000000000000000000000000000000000000000001000000
注册。h
#pragma once
#include <algorithm>
#include <bitset>
#include <string>
#include <vector> // include for typedefs below.
namespace vpc {
typedef std::int8_t i8;
typedef std::int16_t i16;
typedef std::int32_t i32;
typedef std::int64_t i64;
typedef std::uint8_t u8;
typedef std::uint16_t u16;
typedef std::uint32_t u32;
typedef std::uint64_t u64;
const u16 BYTE = 0x08;
const u16 WORD = 0x10;
const u16 DWORD = 0x20;
const u16 QWORD = 0x40;
typedef std::bitset<BYTE> Byte;
typedef std::bitset<WORD> Word;
typedef std::bitset<DWORD> DWord;
typedef std::bitset<QWORD> QWord;
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 Ty>
struct Register : public Register_t<Ty> {
Register() = default;
explicit Register(Ty val) : Register_t<Ty>( val ) {}
};
using Reg8 = Register<u8>;
using Reg16 = Register<u16>;
using Reg32 = Register<u32>;
using Reg64 = Register<u64>;
std::ostream& operator<<(std::ostream& os, const Reg8& reg);
std::ostream& operator<<(std::ostream& os, const Reg16& reg);
std::ostream& operator<<(std::ostream& os, const Reg32& reg);
std::ostream& operator<<(std::ostream& os, const Reg64& reg);
} // namespace vpc
Register.cpp
#include "Register.h"
#include <iostream>
#include <iomanip>
namespace vpc {
std::ostream& operator<<(std::ostream& os, const Reg8& r) {
os << "Reg8(" << +r.currentValue << ")\n"
<< "hex: " << "0x" << std::uppercase
<< std::setfill('0') << std::setw(2) << std::hex
<< +r.currentValue << std::dec << '\n'
<< "bin: " << r.bits << '\n' << std::endl;
return os;
}
std::ostream& operator<<(std::ostream& os, const Reg16& r) {
os << "Reg16(" << r.currentValue << ")\n"
<< "hex: " << "0x" << std::uppercase
<< std::setfill('0') << std::setw(4) << std::hex
<< r.currentValue << std::dec << '\n'
<< "bin: " << r.bits << '\n' << std::endl;
return os;
}
std::ostream& operator<<(std::ostream& os, const Reg32& r) {
os << "Reg32(" << r.currentValue << ")\n"
<< "hex: " << "0x" << std::uppercase
<< std::setfill('0') << std::setw(8) << std::hex
<< r.currentValue << std::dec << '\n'
<< "bin: " << r.bits << '\n' << std::endl;
return os;
}
std::ostream& operator<<(std::ostream& os, const Reg64& r) {
os << "Reg64(" << r.currentValue << ")\n"
<< "hex: " << "0x" << std::uppercase
<< std::setfill('0') << std::setw(16) << std::hex
<< r.currentValue << std::dec << '\n'
<< "bin: " << r.bits << '\n' << std::endl;
return os;
}
} // namespace vpc
这就是我想要的。