C++概念和转换问题

xytpbqjk  于 2023-04-13  发布在  其他
关注(0)|答案(1)|浏览(149)

在以下示例中:

#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));就可以了。
有人能解释一下为什么吗?

2ul0zpep

2ul0zpep1#

在返回类型中对auto放置概念约束的唯一影响是,如果auto被推导为不满足概念的东西,程序将无法编译。除此之外,它没有其他影响。
在您的示例中,multiply(4, 3)multiply的参数类型都推导为int,因此p_val_1 * p_val_2也是int类型,返回类型推导为intint满足std::integral,因此满足概念检查。
然后将multiply(4, 3)int结果转换为其他内容,这完全不受返回类型或函数的概念约束的影响。
使用大括号进行转换是格式错误的,因为使用大括号进行初始化不允许收缩转换,而整数到浮点转换始终允许收缩转换,除非源表达式是其值可以在目标类型中精确表示的常量表达式。在任何情况下,它都不是常量表达式,因为multiply未标记为constexprconsteval
除此之外,任何整数类型都可以隐式转换为任何浮点类型,因此使用任何其他初始化语法,程序都是格式良好的。
所有这些都与multiply的返回类型约束完全无关。

相关问题