c++ useless-cast from size_t to uint32_t for different targets
c++ useless-cast from size_t to uint32_t for different targets
我有一些针对不同目标构建的代码。它还有一些采用 uint32_t 而不是 size_t 的遗留函数——当我想将 size_t 类型转换为它时这很烦人——我们设置了警告级别(很多gcc 警告)。
所以这是一个人为的例子:
val32 = static_cast<uint32_t>(strings.size());
val64 = static_cast<uint64_t>(strings.size()); // ERROR
根据运行在哪个拱门上,上面两行之一会抱怨无用的强制转换警告(我们将其视为错误)。现在我知道有一些解决方法,例如,将代码更改为 size_t... 但是,这不是我的问题。我的问题是,当出现这种情况时,我该如何最好地解决它。
我想出了一个解决方案 - 但它需要变量的引用传递:
template<typename TO, typename FROM>
TO static_cast_if_different(const FROM &value)
{
if constexpr (std::is_same_v<TO, FROM>)
return value;
else
return static_cast<TO>(value);
}
现在这行得通了,但我觉得有更好的方法(也许是标准内置的 - 或者是我在这里所做的改进)?
在此处查看完整的示例代码:https://godbolt.org/z/87hao1aTb
gcc 警告标志的完整列表:-Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wunreachable-code -Wlogical-op -Wshadow -Wmissing-include-dirs -Wparentheses -Wmisleading-indentation -Werror -Wno-psabi -Wno-error=deprecated-declarations -Wnon-virtual-dtor -Wuseless-cast -Wduplicated-cond -Wnull-dereference
注意:我不想删除 useless-cast 警告标志,因为它在其他地方很有用
这个方案不错,还有待改进。
转换和 std::is_same_v
并不是真正必要的。一个简单的赋值将做完全相同的事情(当使用 unsigned
整数类型时,但我们想检查一下)。该函数可能如下所示:
template<typename TO, typename FROM>
TO legacy_size_cast(FROM value)
{
static_assert(std::is_unsigned_v<FROM> && std::is_unsigned_v<TO>,
"Only unsigned types can be cast here!");
TO result = value;
return result;
}
您仍然会在调用站点看到类型转换的视觉指示,我想这就是您想要的。但是,如果您出于某种原因确实需要实际演员表,您仍然可以添加它:
TO result = static_cast<TO>(value);
您可以通过添加以下内容来防止意外溢出:
assert(result == value);
这可能看起来不是很有用(谁会分配一个 4GB 的对象?)但实际上它可以在您传递负偏移量时捕获讨厌的错误,例如(uint64_t)(-1)
。这实际上是一个巨大的正值,但它在算术上表现得像 -1
...直到你将它转换为 uint32_t
然后再转换回 uint64_t
,然后它突然就没有了, assert
会捕捉到。
按引用传递还是按值传递都无所谓。在发布版本中,该函数将完全内联和优化。
我建议使用宏。
例如
#ifdef SOME_ARCH
code
#else
other code
#endif
然后当您为 some_arch 编译时,将 -D SOME_ARCH
添加到编译标志。
我有一些针对不同目标构建的代码。它还有一些采用 uint32_t 而不是 size_t 的遗留函数——当我想将 size_t 类型转换为它时这很烦人——我们设置了警告级别(很多gcc 警告)。
所以这是一个人为的例子:
val32 = static_cast<uint32_t>(strings.size());
val64 = static_cast<uint64_t>(strings.size()); // ERROR
根据运行在哪个拱门上,上面两行之一会抱怨无用的强制转换警告(我们将其视为错误)。现在我知道有一些解决方法,例如,将代码更改为 size_t... 但是,这不是我的问题。我的问题是,当出现这种情况时,我该如何最好地解决它。
我想出了一个解决方案 - 但它需要变量的引用传递:
template<typename TO, typename FROM>
TO static_cast_if_different(const FROM &value)
{
if constexpr (std::is_same_v<TO, FROM>)
return value;
else
return static_cast<TO>(value);
}
现在这行得通了,但我觉得有更好的方法(也许是标准内置的 - 或者是我在这里所做的改进)?
在此处查看完整的示例代码:https://godbolt.org/z/87hao1aTb
gcc 警告标志的完整列表:-Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wunreachable-code -Wlogical-op -Wshadow -Wmissing-include-dirs -Wparentheses -Wmisleading-indentation -Werror -Wno-psabi -Wno-error=deprecated-declarations -Wnon-virtual-dtor -Wuseless-cast -Wduplicated-cond -Wnull-dereference
注意:我不想删除 useless-cast 警告标志,因为它在其他地方很有用
这个方案不错,还有待改进。
转换和
std::is_same_v
并不是真正必要的。一个简单的赋值将做完全相同的事情(当使用unsigned
整数类型时,但我们想检查一下)。该函数可能如下所示:template<typename TO, typename FROM> TO legacy_size_cast(FROM value) { static_assert(std::is_unsigned_v<FROM> && std::is_unsigned_v<TO>, "Only unsigned types can be cast here!"); TO result = value; return result; }
您仍然会在调用站点看到类型转换的视觉指示,我想这就是您想要的。但是,如果您出于某种原因确实需要实际演员表,您仍然可以添加它:
TO result = static_cast<TO>(value);
您可以通过添加以下内容来防止意外溢出:
assert(result == value);
这可能看起来不是很有用(谁会分配一个 4GB 的对象?)但实际上它可以在您传递负偏移量时捕获讨厌的错误,例如
(uint64_t)(-1)
。这实际上是一个巨大的正值,但它在算术上表现得像-1
...直到你将它转换为uint32_t
然后再转换回uint64_t
,然后它突然就没有了,assert
会捕捉到。按引用传递还是按值传递都无所谓。在发布版本中,该函数将完全内联和优化。
我建议使用宏。 例如
#ifdef SOME_ARCH
code
#else
other code
#endif
然后当您为 some_arch 编译时,将 -D SOME_ARCH
添加到编译标志。