英文:
Is it possible to declare a type with a set bit width in c++ without using a struct?
问题
C++中是否支持不使用struct、class或union位域来指定类型的位宽?使用它们会增加不必要且让人讨厌的间接性级别。
如果C++有类似C#的属性,你可以将Address设置为一个访问器,隐藏掉这种间接性。在Ada中,你可以这样声明Address:
type Address is range 0..2**4 - 1 with Object_Size = 4; -- 这不是很可爱吗!
我尝试了以下声明,理论上应该能工作:
typedef unsigned char Address:4; // 如果我们有这么幸运的话!
C++是否支持这样的构造或解决方法?
英文:
It's been at least a decade since I last touched C++. Supposedly, C++ has had a minor overhaul. Is there a way to specify the bit width of a type without using struct, class, or union bitfields? The problem with them is that it adds an unnecessary and annoying level of indirection:
struct Address
{
unsigned char val:4 = 0; // C++ in 2020?
};
struct Device
{
Address address; // 4-bit address
string name;
};
int main()
{
Device device;
device.address.val = 0x8; // Yuckity yuck WTF!
return 0;
};
If C++ had properties like C#, you could make Address an accessor that hides away the indirection. In Ada, you would simply declare Address like so:
type Address is range 0..2**4 - 1 with Object_Size = 4; -- Isn't this cute and sweet!
I tried the following declaration and there's no reason why it shouldn't work:
typedef unsigned char Address:4; // if we were only so lucky!
Does C++ support such a construct or workaround?
答案1
得分: 1
以下是您提供的代码的翻译部分:
不是开箱即用的,但制作一个小的包装类来进行验证并不难。这里是这种类的草图,甚至可以在编译时进行检查。
演示链接:https://onlinegdb.com/RBVQfsAI5
#include <iostream>
// N是您想要使用的地址位数
template<std::size_t N>
struct address_t
{
public:
explicit constexpr address_t(std::uintptr_t value) :
address{ checked_value(value) }
{
}
// 这是少数情况下隐式转换有用的地方
operator std::uintptr_t() const noexcept
{
return address;
}
// 赋值运算符检查值。
void operator=(std::uintptr_t value)
{
address = checked_value(value);
}
private:
constexpr std::uintptr_t checked_value(std::uintptr_t value)
{
if (value >= (1 << N)) throw std::invalid_argument("地址值过大");
return value;
}
std::uintptr_t address;
};
int main()
{
// addres_t<4> 表示最多有 4 位的地址
static constexpr address_t<4> compile_time_address{15}; // 如果值过大,将无法编译通过
std::cout << compile_time_address << "\n"; // 使用隐式转换到 std::uint_ptr_t
address_t<4> runtime_address{15};
std::cout << runtime_address << "\n";
runtime_address = 12;
std::cout << runtime_address << "\n";
try
{
// 在运行时分配无效值会抛出异常。
address_t<4> runtime_address_fail{16};
}
catch (const std::invalid_argument&)
{
}
return 0;
}
请注意,翻译只包括代码部分,不包括问题或其他内容。如果您需要进一步的帮助,请随时提问。
英文:
Not out of the box, but it is not so hard to make a small wrapper class that does the validation. Sketch of such a class here, it can even check at compile time.
Demo here : https://onlinegdb.com/RBVQfsAI5
#include <iostream>
// N is the number of address bits you want to use
template<std::size_t N>
struct address_t
{
public:
explicit constexpr address_t(std::uintptr_t value) :
address{ checked_value(value) }
{
}
// one of the rare cases implicit conversion is useful
operator std::uintptr_t() const noexcept
{
return address;
}
// assigment operator checks the value.
void operator=(std::uintptr_t value)
{
address = checked_value(value);
}
private:
constexpr std::uintptr_t checked_value(std::uintptr_t value)
{
if (value >= (1 << N)) throw std::invalid_argument("address value too large");
return value;
}
std::uintptr_t address;
};
int main()
{
//addres_t<4> means an address with max. 4 bits
static constexpr address_t<4> compile_time_address{15}; // will not compile if value too big
std::cout << compile_time_address << "\n"; // uses implicit conversion to std::uint_ptr_t
address_t<4> runtime_address{15};
std::cout << runtime_address << "\n";
runtime_address = 12;
std::cout << runtime_address << "\n";
try
{
// at runtime assigning an invalid value will throw.
address_t<4> runtime_address_fail{16};
}
catch (const std::invalid_argument&)
{
}
return 0;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论