使用std :: uint8_t作为键初始化地图时的警告 1禁用此部分的警告 2显式转换每个键

问题描述

问题

我正在尝试创建std::uint8_t-> char的地图,并使用一些值对其进行初始化:

const std::map<std::uint8_t,char> ScenarioReader::alphabet = {
    { 0x12,'b' },{ 0x13,'c' },{ 0x15,'a' },{ 0x16,'f' },...
}

这会生成一个编译器警告,因为这些整数文字0x12等被识别为unsigned ints,它们比std::uint8_t大:

1>d:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\utility(172): warning C4244: 'initializing': conversion from '_Ty' to '_Ty1',possible loss of data
1>        with
1>        [
1>            _Ty=unsigned int
1>        ]
1>        and
1>        [
1>            _Ty1=uint8_t
1>        ]
1>d:\my-project\src\myfile.cpp(75): note: see reference to function template instantiation 'std::pair<const _Kty,_Ty>::pair<unsigned int,char,0>(_Other1 &&,_Other2 &&) noexcept' being compiled
1>        with
1>        [
1>            _Kty=uint8_t,1>            _Ty=char,1>            _Other1=unsigned int,1>            _Other2=char
1>        ]
1>d:\my-project\src\myfile.cpp(12): note: see reference to function template instantiation 'std::pair<const _Kty,1>            _Other2=char
1>        ]

解决方

我知道有两种方法可以解决此问题:

1)禁用此部分的警告

#pragma warning( push )
#pragma warning( disable : 4244 )
const std::map<std::uint8_t,...
}
#pragma warning( pop)

2)显式转换每个键

const std::map<std::uint8_t,char> ScenarioReader::alphabet = {
    { static_cast<std::uint8_t>(0x12),{ static_cast<std::uint8_t>(0x13),{ static_cast<std::uint8_t>(0x15),{ static_cast<std::uint8_t>(0x16),...
}

我对这两种方法都不特别满意,但是第二种方法对我来说尤其难看。

也许我缺少一个简单的解决方案吗?

解决方法

integer literal永远不能是std::uint8_t。您可以使用文字的explicit cast来代替static_cast

const std::map<std::uint8_t,char> alphabet = {
    { std::uint8_t(0x12),'b' },{ std::uint8_t(0x13),'c' },{ std::uint8_t(0x15),'a' },{ std::uint8_t(0x16),'f' },};
,

警告是错误的警告,仅在\W4警告级别上发生。

从文字到std::uint8_t的转换不应产生任何警告,除非文字超出了转换为类型的范围,在这里不是这种情况。

我认为您选择的任何选项都可以。它只是归结为个人喜好问题。我个人更喜欢std::uint8_t{0x12}语法。

另一种选择是将警告级别降低到\W3,然后使用单独的短绒棉(\W4主要是used for lint-like warnings)。

,

您可以编写用户定义的文字

#include <cstdint>

constexpr std::uint8_t operator "" _ui8(unsigned long long value)
{
    return static_cast<std::uint8_t>(value);
}

#include <type_traits>

int main() {
    static_assert(std::is_same_v<decltype(0x12_ui8),std::uint8_t>);
}