std::to_integer的目的是什么?

17
据我所知,std::to_integer<T> 相当于 T(value),其中 value 是一个类型为 std::byte 的变量。我查看了一些主要编译器的实现,发现在这种情况下,“相当于”字面上意思是“作为实现”。换句话说,在大多数情况下,to_integer 实际上被实现为:
return T(value);

就是这样。

我不明白这样一个函数的目的是什么?
具有讽刺意味的是,它的缺点甚至比优点还要多。我应该为这样一个函数包括整个头文件,只是为了避免类似C语言的强制转换,而这种转换很可能直接内联。

除了作为类似C语言强制转换的“好看”替代品之外,还有其他原因吗?


5
标题的抱怨是不公平的。如果您使用std::byte,那个头文件已经被包含了(或者最好被包含了!) - StoryTeller - Unslander Monica
1
std::to_integer<T> 是一个 constexpr,但对于 T(value) 并不一定相同。 - Silvano Cerza
2
@SilvanoCerza 它实际上是作为一个constexpr函数实现的,它返回T(value)。它怎么可能不同于T(value)呢?我不明白,但听起来很有趣,如果可能的话,我邀请您在答案中更好地阐述这一点。谢谢。 - skypjack
我认为这可能与ADL有关,但我不确定。 - David G
4个回答

22
这只是C风格转换的一个好看且无害的替代品吗?
你把它说得好像这是一些琐碎的细节。强制类型转换是危险的。将某些东西转换为错误的类型很容易,而且通常编译器不会阻止你这样做。此外,因为在C++中,std::byte 不是整数类型,所以处理数字字节值通常需要大量强制类型转换。拥有一个可以明确转换为整数的函数可以使用户体验更加安全。
例如,float(some_byte) 是完全合法的,而 to_integer<float>(some_byte) 是明确禁止的。 to_integer<T> 要求 T 是整数类型。 to_integer 是一个更安全的选择。
我应该为这样一个函数包含一个完整的头文件吗?
如果你指的是 "整个头文件",那么你已经从中获取了std::byte,因此根据定义已经包含了相同的头文件...

10

std::to_integer<T>(some_byte) 相当于 T(some_byte),但前提是它能够编译通过。 T(some_byte) 等同于不安全的 C 风格强制类型转换 (T)some_byte,可能会产生可怕的后果。另一方面,std::to_integer 受到适当限制,只有在安全的情况下才能工作:

只有当 std::is_integral_v<IntegerType> 为真时,此重载才参与重载决议。

如果 T 不是整数类型,那么代码将无法编译而不是产生未定义的行为。如果 some_byte 不是 std::byte,那么代码将无法编译而不是产生未定义的行为。


你有一个从非指针类型转换为整数类型的未定义行为的例子吗(特别是从非指针类型,可能实现会选择未定义行为)? - Davis Herring
@DavisHerring 我非常谨慎地选择了“可能具有未定义行为”的短语。如果您执行不正确的转换并使用该转换的结果,则会出现未定义的行为。例如,如果 T 实际上是一个指针,如果 some_byte 实际上是一个指针,如果其中一个是引用(我必须仔细考虑规则才能知道何时引用是正确的)。重点是 C 风格转换的接口允许您做危险和不安全的事情,但 std::to_integer 不会这样做。 - Justin
@DavisHerring,此外,实现不能“选择未定义的行为”;这不取决于实现。标准决定某些行为是否被定义。实现不能选择使某些行为未定义。他们可以选择定义未定义的行为,但他们不能取消已定义的行为。 - Justin
表达式从不具有引用类型,而对非引用类型的强制转换仅涉及源的值类别,仅在调用函数时才会涉及。至于“实现定义的未定义行为”,我之所以说“可能”是出于与您说“潜在”的原因相同——实现可以合理地表示将整数转换为指针涉及通过(可能无效的)指针读取等操作。 - Davis Herring

4
除了之前提到的意图表达和安全问题外,我从委员会讨论论文中得出的想法是,它的目的就像std::to_string一样,并且未来可能会有更多的重载版本。

1
这是一个很好的观点。通过引用一些委员会讨论并解释讨论如何暗示这一点,可以改进它,但未来的演变是std::to_integer的原因是有道理的。 - Justin
1
@Justin:精确的会议记录不会被公开,但是也没有太多可引用的内容(除了与 to_string 的比较之外)——因此是“我明白了”。我认为还有可能正在考虑不支持 static_cast<int>(myByte) 的替代设计。 - Davis Herring

3

C风格的强制类型转换与std::to_integer<T>不等价。请看下面的示例。

std::to_integer<T>仅在std::is_integral_v<T>为true时参与重载决议。

#include <cstddef>
#include <iostream>

template <typename T>
auto only_return_int_type_foo(std::byte& b)
{
    return std::to_integer<T>(b);
}

template <typename T>
auto only_return_int_type_bar(std::byte& b)
{
    return T(b);
}

int main()
{
    std::byte test{64};
    // compiles
    std::cout << only_return_int_type_foo<int>(test) << std::endl;

    // compiler error
    std::cout << only_return_int_type_foo<float>(test) << std::endl;

    // compiles
    std::cout << only_return_int_type_bar<int>(test) << std::endl;

    // compiles
    std::cout << only_return_int_type_bar<float>(test) << std::endl;
} 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接