字面值到类类型的隐式转换是在编译时发生吗?

6

我正在尝试编写一个与整数密切相关的类,因此我包含了一个形式为

conversion constructor

的转换构造函数。

constexpr example::example(const int &n);

我的问题是:如果我随后定义了这个函数。
void foo(example n);

我这样使用它

foo(3);

在我的代码中,整数字面量3是否会在编译时转换为example的实例?

如果不是,是否有一种方法可以获得这种行为?

如果是,即使构造函数没有显式声明为constexpr,仍然会发生吗?


你试图解决的真正问题是什么? - R Sahu
1
@RSahu 这个问题是关于值是在编译时还是运行时转换的。这就是问题吗? - Engel
1
听起来你想要使用consteval - NathanOliver
1
我的理解是,只有在需要定义编译时常量的情况下,3 才必须在编译时转换为 example 的实例。否则,它不会被转换。 - R Sahu
我不是完全确定,但我认为除非你像@RSahu所说的那样做,否则它不会被转换。示例 - Ted Lyngmo
@RSahu 如果 example 是一个构造缓慢的复杂对象,并且 foo(3); 在另一个函数内,例如 void bar(){foo(3); return;},那么怎么办?每次调用 bar 时都会将 3 转换一次吗? - ThePirate42
2个回答

4
构造函数声明为constexpr并不意味着计算必须在编译时发生,它仅表示构造函数适用于常量表达式和非常量表达式。
另一方面,如果您将构造函数声明为consteval,那么仅允许常量表达式调用该构造函数。这又意味着每个构造函数的调用都必须由编译器检查以确保它是一个常量表达式(如果不是,则编译器必须诊断出违规)。由于检查某些内容是否是常量表达式需要检查是否包含未定义的行为,因此进行这种检查与实际评估表达式同样困难。因此,声明构造函数(或任何其他函数)consteval将确保函数不会在运行时被调用。编译器被允许生成代码在运行时重新评估它,但没有理由这样做。这种方法的缺点是首先,不可能在非常量表达式中使用构造函数,其次,常量表达式计算比运行时计算慢得多,您必须决定是否值得增加编译时间。
如果将构造函数保留为constexpr,则可以通过使用constexpr变量在特定情况下强制其在编译时调用:
constexpr example ex = 3;  // evaluated at compile time
foo(ex);

这是因为constexpr变量只允许通过常量表达式进行初始化。

如果我使用了 consteval 用户定义字面量会怎样? - ThePirate42
1
@ThePirate42 我认为那会起作用。这类似于一个 consteval 构造函数。 - Brian Bi

1

顺便提一下,使用-O2生成的汇编指令与使用-O3生成的完全相同,而使用-O1生成的汇编指令几乎相同(使用mov eax, 0而不是xor eax, eax将eax置零) - ljleb

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