在以下示例中:
#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));
就可以了。
有人能解释一下为什么吗?
1条答案
按热度按时间2ul0zpep1#
在返回类型中对
auto
放置概念约束的唯一影响是,如果auto
被推导为不满足概念的东西,程序将无法编译。除此之外,它没有其他影响。在您的示例中,
multiply(4, 3)
将multiply
的参数类型都推导为int
,因此p_val_1 * p_val_2
也是int
类型,返回类型推导为int
。int
满足std::integral
,因此满足概念检查。然后将
multiply(4, 3)
的int
结果转换为其他内容,这完全不受返回类型或函数的概念约束的影响。使用大括号进行转换是格式错误的,因为使用大括号进行初始化不允许收缩转换,而整数到浮点转换始终允许收缩转换,除非源表达式是其值可以在目标类型中精确表示的常量表达式。在任何情况下,它都不是常量表达式,因为
multiply
未标记为constexpr
或consteval
。除此之外,任何整数类型都可以隐式转换为任何浮点类型,因此使用任何其他初始化语法,程序都是格式良好的。
所有这些都与
multiply
的返回类型约束完全无关。