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

Returning new object from function defined using Concepts

代码

#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


那我该如何解决呢?

关于编译器为何无法推断 return 类型的解释也会有所帮助。

VectorXY 不是类型。这是一个概念,旨在检查从函数中 return 表达式推导出的类型。并且所述类型推导完全独立于推导函数的 参数 .

的类型

你return是什么

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

这是一个花括号封闭的初始化器。当对其进行模板参数推导时,通常推导的是 std::initializer_list。这样做的两个问题是,第一,没有包含相应的 header,所以程序是 ill-formed。其次,即使 header 包括在内,std::initializer_list<float> 也不满足 VectorXY 概念。

您可以通过指定 returned object 的类型来修复它,例如通过功能转换符号

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

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

Live Example.


作为附录,GCC 还没有实现它,但正确的语法应该是

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

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