问题确实出在
decltype(auto)
上。返回类型是通过遵循以下列表进行推断的(所讨论的表达式是给定给返回语句的表达式):
[dcl.type.decltype] (redacted for emphasis)
decltype-specifier:
decltype ( expression )
1 For an expression E, the type denoted by decltype(E) is defined
as follows:
- ...
- ...
- otherwise, if E is an unparenthesized id-expression or an unparenthesized class member access ([expr.ref]), decltype(E) is the
type of the entity named by E. If there is no such entity, or if E
names a set of overloaded functions, the program is ill-formed;
- ...
- ...
< p >
a
的类型是
int [2]
。因此,您实际上正在定义一个带有数组返回类型的函数...但是...
[dcl.fct]
11函数不得具有数组或函数类型的返回类型,尽管它们可以具有指向这些东西的指针或引用类型的返回类型。不能有函数的数组,尽管可以有指向函数的指针数组。
您无意中生成了一个格式错误的函数类型。因此,是的,解决方案就像您注意到的那样,不要使用decltype
。您可以显式返回引用(指向推断出的数组类型),因为这确实是您想要的:
auto& bar() { static int a[2]; return a; }
或者如果您想明确返回类型,而不必进入声明符地狱,您可以在尾随方式中指定它:
auto bar() -> int(&)[2] { static int a[2]; return a; }
无论如何,我认为这比依赖于有时晦涩难懂的decltype
语义要好。当你明确返回一个左值引用(这是你的全部意图)时,就不会出现微妙的错误。
作为旁注,您最后一个问题包含了尚未被规定为合法的声明(虽然由于它们基本上被认为是正确的实现而被接受)。这是
CWG Issue 2397。但其要点是,它的行为就像在函数参数中预期的数组类型一样。
auto [2]
被调整为
auto*
,而
auto(&) [2]
仅绑定到特定类型的数组。这意味着它是一个缩写的函数模板,相当于:
template<typename T>
void f(T[2]);
template<typename T>
void f(T(&)[2]);
返回类型不像参数那样进行调整。参数类型的调整本身是C遗产,我们从中得到了不是一等公民的原始数组。就类型而言,它们相当不规则。如果您需要具有“更健全”的值语义的数组,则可以使用
std::array
来实现此目的。
return (a);
? - Yakk - Adam Nevraumontauto &
是一个引用,对于初学者来说,其中包含的问题要少得多。 - StoryTeller - Unslander Monica