英文:
std::pair<auto, auto> return type
问题
以下是您要翻译的内容:
EXAMPLE 1
template <unsigned S>
auto f()
{
if constexpr (S == 1)
return std::pair{1, 2}; // pair of ints
else if constexpr (S == 2)
return std::pair{1.0, 2.0}; // pair of doubles
else
return std::pair{0.0f, 0.0f}; // pair of floats
}
这段代码在gcc 9.2、gcc 10.0、clang 9.0和clang 10.0中都有效。
接下来,出于清晰度的原因,我想明确地将返回类型写为std::pair
:
EXAMPLE 2
template <unsigned S>
std::pair<auto, auto> f()
{
if constexpr (S == 1)
return {1, 2};
/* ... */
}
无论是gcc 9.2/10.0还是clang 9.0/10.0,都无法编译这段代码。
gcc 9.2
error: invalid use of 'auto'
error: template argument 1 is invalid // first argument (auto) of std::pair
error: template argument 2 is invalid // second argument (auto) of std::pair
error: cannot convert '<brace-enclosed initializer list>' to 'int' in return
从最后一个错误消息来看,gcc 9.2似乎认为std::pair<auto, auto>
是一个int
。这如何解释?
gcc 10.0
error: returning initializer list
这个错误是可以理解的,但是我期望会调用std::pair
的构造函数,或者我在这里漏掉了什么?
clang 9.0和10.0
'auto' not allowed in template argument
excess elements in scalar initializer
no matching function for call to 'f'
好吧,clang不喜欢这些。从第二个错误消息来看,clang也认为返回类型是int
。
最后,为了修复使用gcc 10.0编译时获得的错误,我决定明确返回一个std::pair
:
EXAMPLE 3
template <unsigned S>
std::pair<auto, auto> f()
{
if constexpr (S == 1)
return std::pair{1, 2};
/* ... */
}
clang 9.0和10.0
与之前相同,但还有一个额外的错误:
no viable conversion from returned value of type 'std::pair<int, int>' to function return type 'int'
在这里,clang仍然认为我们正在返回一个int
?
gcc 9.2
与之前相同。
gcc 10.0
它有效!
我猜有些功能可能仍需实现,或者在上述情况中,是否有一个编译器是正确的,而另一个是错误的?在我看来,示例2应该有效。或者不应该有效吗?
英文:
I was playing around with auto
in std::pair
. In the below code, function f
is supposed to return a std::pair
of types which depend on a template parameter.
A working example:
EXAMPLE 1
template <unsigned S>
auto f()
{
if constexpr (S == 1)
return std::pair{1, 2}; // pair of ints
else if constexpr (S == 2)
return std::pair{1.0, 2.0}; // pair of doubles
else
return std::pair{0.0f, 0.0f}; // pair of floats
}
This works with gcc 9.2, gcc 10.0, clang 9.0 and clang 10.0.
Next, I wanted to explicitly write the return type as a std::pair
for clarity reasons:
EXAMPLE 2
template <unsigned S>
std::pair<auto, auto> f()
{
if constexpr (S == 1)
return {1, 2};
/* ... */
}
Both gcc 9.2/10.0 and clang 9.0/10.0 failed to compile this.
gcc 9.2
error: invalid use of 'auto'
error: template argument 1 is invalid // first argument (auto) of std::pair
error: template argument 2 is invalid // second argument (auto) of std::pair
error: cannot convert '<brace-enclosed initializer list>' to 'int' in return
From the last error message, gcc 9.2 seems to believe that std::pair<auto, auto>
is an int
. How can this be explained?
gcc 10.0
error: returning initializer list
This error is understandable, however, I expected the constructor of std::pair
to be invoked, or is there something I am missing here?
clang 9.0 and 10.0
'auto' not allowed in template argument
excess elements in scalar initializer
no matching function for call to 'f'
Ok, clang doesn't like any of this. From the second error message, it seems that clang also believes the return type is int
.
Finally, to fix the error obtained compiling with gcc 10.0, I decided to return a std::pair
explicitly:
EXAMPLE 3
template <unsigned S>
std::pair<auto, auto> f()
{
if constexpr (S == 1)
return std::pair{1, 2};
/* ... */
}
clang 9.0 and 10.0
Same as before, but with an additional:
no viable conversion from returned value of type 'std::pair<int, int>' to function return type 'int'
Here clang still thinks we are returning an int
?
gcc 9.2
Same as before.
gcc 10.0
It works!
I guess some features still have to be implemented, or in one of the situations described above, is there a compiler which is right and the other wrong? In my opinion, example 2 should work. Or should it not?
答案1
得分: 23
以下是翻译好的部分:
原文:
The syntax:
std::pair<auto, auto> f() { return std::pair(1, 2); }
翻译:
语法:
std::pair<auto, auto> f() { return std::pair(1, 2); }
原文:
Was part of the original Concepts TS but was not included in the Concepts proposal that is part of C++20. As such, the only placeholder types in C++20 are auto
(and variations thereof like auto**
), decltype(auto)
, and constrained placeholders (Concept auto
and variations thereof). This kind of nested placeholder type would be very useful, but is not part of C++20, so that function declaration is ill-formed.
翻译:
这种语法曾经是原始概念(Concepts TS)的一部分,但没有包含在C++20的概念提案中。因此,在C++20中唯一的占位类型是auto
(以及类似auto**
的变体)、decltype(auto)
和受限制的占位符(Concept auto
及其变体)。这种嵌套的占位符类型会非常有用,但它不属于C++20的一部分,因此该函数声明是不合法的。
原文:
Now, gcc allows it because gcc implemented the Concepts TS and I guess they decided to keep this feature. clang never implemented the TS, so it doesn't.
翻译:
现在,GCC允许它,因为GCC实现了概念(Concepts)TS,我猜他们决定保留这个特性。而Clang从未实现过这个TS,因此不支持它。
原文:
Either way, this:
std::pair<auto, auto> f() { return {1, 2}; }
Would always be ill-formed. The meaning of the syntax is that we deduce the return type and then require that it matches pair<T, U>
for some types T
and U
. We're basically trying to invoke the invented function:
template <typename T, typename U>
void __f(std::pair<T, U>);
__f({1, 2}); // this must succeed
翻译:
无论如何,这个语句:
std::pair<auto, auto> f() { return {1, 2}; }
都将始终是不合法的。这个语法的意义是我们推断返回类型,然后要求它匹配某些类型T
和U
的pair<T, U>
。实际上,我们正在尝试调用这个虚构的函数:
template <typename T, typename U>
void __f(std::pair<T, U>);
__f({1, 2}); // 这必须成功
原文:
But you cannot deduce a type from {1, 2}
- a braced-init-list doesn't have a type. Perhaps this is something that should be explored (as it's easy to understand at least in a simple case like this), but it has never been allowed. So rejecting it is correct either way.
翻译:
但你不能从{1, 2}
中推断出一个类型 - 花括号初始化列表(braced-init-list)没有类型。也许这是一个值得探讨的问题(因为至少在像这样的简单情况中很容易理解),但从来没有被允许。因此,无论如何都拒绝它都是正确的。
原文:
Lastly:
> gcc 9.2 seems to believe that std::pair<auto, auto>
is an int
. How can this be explained?
For some reason (probably due to our C legacy with implicit int
), when gcc does not recognize or understand a type, it just uses int
as the placeholder in error messages. This is super confusing, because obviously it's gcc that came up with int
and not the source code. But that's the way it is.
翻译:
最后:
> GCC 9.2似乎认为std::pair<auto, auto>
是一个int
。这可以如何解释?
出于某种原因(可能是由于我们在C中的遗留问题,隐式使用int
),当GCC不能识别或理解一个类型时,它只是在错误消息中使用int
作为占位符。这非常令人困惑,因为显然是GCC提出了int
,而不是源代码。但事实就是如此。
英文:
The syntax:
std::pair<auto, auto> f() { return std::pair(1, 2); }
~~~~~~~~~~~~~~~~~~~~~
Was part of the original Concepts TS but was not included in the Concepts proposal that is part of C++20. As such, the only placeholder types in C++20 are auto
(and variations thereof like auto**
), decltype(auto)
, and constrained placeholders (Concept auto
and variations thereof). This kind of nested placeholder type would be very useful, but is not part of C++20, so that function declaration is ill-formed.
Now, gcc allows it because gcc implemented the Concepts TS and I guess they decided to keep this feature. clang never implemented the TS, so it doesn't.
Either way, this:
std::pair<auto, auto> f() { return {1, 2}; }
Would always be ill-formed. The meaning of the syntax is that we deduce the return type and then require that it matches pair<T, U>
for some types T
and U
. We're basically trying to invoke the invented function:
template <typename T, typename U>
void __f(std::pair<T, U>);
__f({1, 2}); // this must succeed
But you cannot deduce a type from {1, 2}
- a braced-init-list doesn't have a type. Perhaps this is something that should be explored (as it's easy to understand at least in a simple case like this), but it has never been allowed. So rejecting it is correct either way.
Lastly:
> gcc 9.2 seems to believe that std::pair<auto, auto>
is an int
. How can this be explained?
For some reason (probably due to our C legacy with implicit int
), when gcc does not recognize or understand a type, it just uses int
as the placeholder in error messages. This is super confusing, because obviously it's gcc that came up with int
and not the source code. But that's the way it is.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论