【问题标题】:constexpr function gets value at compile time even though my variable is not constexprconstexpr 函数在编译时获取值,即使我的变量不是 constexpr
【发布时间】:2019-12-18 00:47:50
【问题描述】:

我正在尝试使用https://github.com/gdelugre/literal_ipaddr,它说它是一个

inet_addr/inet_aton/inet_pton 的 C++17 constexpr 实现

当我这样做时:

auto ipSourceAddressTest = IPAddr::inet_pton<AF_INET>("127.0.0.1");
std::cout << "ipSourceAddressTest is " << ipSourceAddressTest.s_addr << std::endl;

这很好用。我得到十进制的 IP 地址。

但是:

std::string ipv4address;
//get ipv4address from world here
const unsigned int ipMaxSize = 200;
char ip[ipMaxSize];
std::copy(ipv4address.begin(), ipv4address.end(), ip);
auto ipSourceAddress = IPAddr::inet_pton<AF_INET>(ip);
std::cout << "ipSourceAddress is " << ipSourceAddress.s_addr << std::endl;

记住ipSourceAddress.s_addruint32_t。我打印的值不是十进制的 IP,而是4294967295,即二进制的111...111。所以我认为它在编译时而不是运行时获得了它的价值。

如果我这样做了

constexpr auto in_addr1 = IPAddr::inet_pton<AF_INET>(ip);

那么它的值将在编译时推导出来是可以理解的。但是我没有在我的变量声明中使用constexprauto 是否暗示constexpr

根据https://en.cppreference.com/w/cpp/language/constexpr

在函数或静态成员变量中使用的 constexpr 说明符 (C++17 起) 声明意味着内联

那么为什么函数inet_pton 会在编译时获得它的价值?

【问题讨论】:

  • 你怎么知道它是在编译时计算的?你看过生成的程序集吗?注意:您的 ip 数组未初始化(因为 ipv4address 为空,因此 std::copy 什么也不做),因此使用它是未定义的行为。
  • 可以在运行时调用constexpr 函数。如果可能,它只会在编译时计算。
  • @AlgirdasPreidžius ipv4address 不是空的,在评论中我是从世界上得到的。
  • @GuerlandoOCs "ipv4address 不是空的,在评论中我是从世界上得到的。" 然后,请提供minimal reproducible example。更多信息:ipIPAddr::inet_pton&lt;AF_INET&gt;(ip); 中是否被视为以空字符结尾的字符串(C 字符串)?如果是这样,这是未定义的行为,即使 ipv4address 不为空,因为 std::copy 不会复制空终止符。
  • @KaenbyouRin 查看该库,它似乎主要用于编译时使用,并且仅接受 char 数组,而不接受指针。

标签: c++ c++17


【解决方案1】:

ipSourceAddress 在编译时没有得到它的值(as-if 规则不受约束)。

ip 的值不能在常量表达式中使用,因为它没有声明为constexpr,并且不符合常量表达式中左值到右值转换规则的其他例外情况之一。因此IPAddr::inet_pton&lt;AF_INET&gt;(ip) 不是常量表达式。

您可以通过 ipSourceAddress constexpr 清楚地看到这一点(auto 并不暗示)。

变量上的constexpr 需要在编译时初始化,因为初始化器不是常量表达式,所以它会失败。

godbolt

我不知道你是怎么得出不同结论的。


但请注意,该库似乎确实要求传递给它的 char 数组与其包含的字符串完全相同(加上空终止符)。如果你给它一个更长的数组并输出你看到的值,它会失败。

godbolt

似乎作者打算只用字符串文字直接调用函数。

【讨论】:

  • 因此,如果“变量上的 constexpr 需要在编译时初始化”,那么这意味着我不能以任何方式使用 IPAddr::inet_pton&lt;AF_INET&gt;(ip),除非在编译时已知值?为什么有人会创建这样一个有限的图书馆?
  • @GuerlandoOCs 不,如果你不使用constexpr,它将在运行时执行,没有问题。您不需要constexpr。话虽如此,在查看了该库之后,作者似乎确实考虑了编译时间,因为他们没有提供采用char* 的重载以供纯运行时使用。你到底为什么需要这个库?为什么不直接使用 POSIX 函数呢?
  • 但我没有使用constexpr。我只是做了auto ipSourceAddress = IPAddr::inet_pton&lt;AF_INET&gt;(ip);
  • @GuerlandoOCs 是的,这并没有错。我不明白你遇到了什么问题。
  • 问题是,我得到的不是十进制版本的 IP 地址 (192.168.255.18),而是4294967295,即二进制的111...111。我什至在调用inet_pton 之前添加了一个std::cout,它确实正确地打印了IP 地址ip。但是,如果我这样做,而是使用 constexpr 像这样:constexpr auto in_addr1 = IPAddr::inet_pton&lt;AF_INET&gt;("192.168.255.18"); 我得到一个真正的十进制值。
猜你喜欢
  • 2020-03-06
  • 2014-01-08
  • 1970-01-01
  • 1970-01-01
  • 2023-01-05
  • 1970-01-01
  • 2020-10-08
  • 1970-01-01
  • 2021-02-13
相关资源
最近更新 更多