c++概念和转换问题



示例如下:

#include <concepts>
#include <cstdint>
#include <iostream>
using namespace std;
integral auto multiply(integral auto p_val_1, integral auto p_val_2) {
return p_val_1 * p_val_2;
}
int main() {
{
float f{multiply(4, 3)};
cout << "f = " << f << endl;
}
{
float f(multiply(4, 3));
cout << "f = " << f << endl;
}
{
constexpr uint16_t i1{4};
constexpr uint16_t i2{3};
float f{multiply(i1, i2)};
cout << "f = " << f << endl;
}
{
constexpr int i1{4};
constexpr int i2{3};
float f(multiply(i1, i2));
cout << "f = " << f << endl;
}
return 0;
}

gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0,在float f{multiply(4, 3)};,报告

main.cpp:13:13: Non-constant-expression cannot be narrowed from type 'int' to 'float' in initializer list (fix available)
insert an explicit cast to silence this issue

,在float f{multiply(i1, i2)};中,它报告

main.cpp:25:13: Non-constant-expression cannot be narrowed from type 'int' to 'float' in initializer list (fix available)
insert an explicit cast to silence this issue

在我(仍然)对概念的理解很差的情况下,不应该将multiply的结果分配给不满足std::integral要求的对象,但使用float f(multiply(i1, i2));float f(multiply(4, 3));是可以的。

有谁能解释一下为什么吗?

在返回类型中对auto施加概念约束的唯一效果是,如果将auto推导为不满足概念的值,则程序将无法编译。除此之外,没有别的效果。

在您的示例中,multiply(4, 3)multiply的参数类型推断为int,因此p_val_1 * p_val_2也属于int类型,返回类型推断为intint满足std::integral,因此概念检查满足。

然后将multiply(4, 3)int结果转换为其他内容完全不受返回类型或函数上的概念约束的影响。


使用大括号的转换是错误的,因为使用大括号的初始化不允许窄化转换,而整型到浮点型的转换总是允许窄化转换,除非源表达式是一个常量表达式,其值可以精确地用目标类型表示。在所有情况下,它都不是常量表达式,因为multiply没有标记为constexprconsteval

除此之外,任何整型都可以隐式转换为任何浮点型。因此,使用任何其他初始化语法,程序都是格式良好的。

所有这些都完全独立于multiply返回类型的约束。

最新更新