std::pair<auto, auto> 返回类型

huangapple go评论75阅读模式
英文:

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 &lt;unsigned S&gt;
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 &lt;unsigned S&gt;
std::pair&lt;auto, auto&gt; 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 &#39;auto&#39;
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 &#39;&lt;brace-enclosed initializer list&gt;&#39; to &#39;int&#39; in return

From the last error message, gcc 9.2 seems to believe that std::pair&lt;auto, auto&gt; 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

&#39;auto&#39; not allowed in template argument
excess elements in scalar initializer
no matching function for call to &#39;f&#39;

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 &lt;unsigned S&gt;
std::pair&lt;auto, auto&gt; 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 &#39;std::pair&lt;int, int&gt;&#39; to function return type &#39;int&#39;

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&lt;auto, auto&gt; 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&lt;T, U&gt; 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}; }
都将始终是不合法的。这个语法的意义是我们推断返回类型,然后要求它匹配某些类型TUpair&lt;T, U&gt;。实际上,我们正在尝试调用这个虚构的函数:
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&lt;auto, auto&gt; 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&lt;auto, auto&gt;是一个int。这可以如何解释?
出于某种原因(可能是由于我们在C中的遗留问题,隐式使用int),当GCC不能识别或理解一个类型时,它只是在错误消息中使用int作为占位符。这非常令人困惑,因为显然是GCC提出了int,而不是源代码。但事实就是如此。

英文:

The syntax:

std::pair&lt;auto, auto&gt; 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&lt;auto, auto&gt; 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&lt;T, U&gt; for some types T and U. We're basically trying to invoke the invented function:

template &lt;typename T, typename U&gt;
void __f(std::pair&lt;T, U&gt;);

__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&lt;auto, auto&gt; 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.

huangapple
  • 本文由 发表于 2020年1月3日 20:21:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/59578575.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定