从使用概念定义的函数返回新对象

Returning new object from function defined using Concepts

本文关键字:新对象 返回 对象 函数 定义      更新时间:2023-10-16

Code

#include <type_traits>
template <typename N>
concept Number = std::is_arithmetic<N>::value;
template <typename T>
concept VectorXY = requires(T t)
{
{t.x} -> Number;
{t.y} -> Number;
};
template <Number N>
struct Vec2
{
N x = 0;
N y = 0;
};
VectorXY operator*(VectorXY v, Number n)
{
return {v.x * n, v.y * n};
// error: returning initializer list
}
int main()
{
Vec2<float> v = Vec2<float>{} * 1;
// error: conversion from 'void' to non-scalar type 'Vec2<float>' requested
}

神霹雳:https://godbolt.org/z/gYsQ5B


那么我该如何解决这个问题呢?

解释为什么编译器无法推断返回类型也会有所帮助。

VectorXY

不是一种类型。这是一个概念,旨在检查从函数返回的表达式推导出的类型。并且所述类型推导与推导函数参数的类型完全分开。

您返回的是

{v.x * n, v.y * n}

它是一个支撑封闭的初始值设定项。在对它进行模板参数推导时,通常推导出的是一个std::initializer_list。这样做的两个问题是,首先,不包括相应的标头,因此程序格式不正确。其次,即使包含标题,std::initializer_list<float>也不能满足VectorXY概念。

您可以通过指定返回对象的类型来修复它,例如通过函数强制转换表示法

return decltype(v){v.x * n, v.y * n};

现在它是一个类型化表达式,根据该表达式,函数的返回类型被推导出为满足VectorXY概念的东西。

活生生的例子。


作为附录,GCC 尚未实现它,但正确的语法应该是

VectorXY auto operator*(VectorXY auto v, Number auto n)
{
return decltype(v){v.x * n, v.y * n};
}

鉴于仅使用VectorXY引起的混乱,我认为委员会要求这种受约束的auto语法是正确的。在这里,正在进行类型推断的事实对我来说更为明显。