标准::p空气<自动,自动>返回类型



我在std::pairauto。在下面的代码中,函数f应该返回依赖于模板参数的std::pair类型。

一个工作示例:

例 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

例 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 都无法编译它。

海湾合作委员会 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.这怎么解释呢?

海湾合作委员会 10.0

error: returning initializer list

这个错误是可以理解的,但是,我希望调用std::pair的构造函数,还是我在这里缺少什么?

叮当 9.0 和 10.0

'auto' not allowed in template argument
excess elements in scalar initializer
no matching function for call to 'f'

好吧,叮当不喜欢这些。从第二条错误消息来看,clang 似乎也认为返回类型是int

最后,为了修复使用 gcc 10.0 编译时获得的错误,我决定显式返回一个std::pair

例 3

template <unsigned S>
std::pair<auto, auto> f()
{
if constexpr (S == 1)
return std::pair{1, 2};
/* ... */
}

叮当 9.0 和 10.0

与以前相同,但增加了一个:

no viable conversion from returned value of type 'std::pair<int, int>' to function return type 'int'

在这里,叮当仍然认为我们正在返回int

海湾合作委员会 9.2

和以前一样。

海湾合作委员会 10.0

它有效!

我想仍然需要实现一些功能,或者在上述情况之一中,是否有一个编译器是对的,另一个是错的?在我看来,示例 2 应该有效。还是不应该?

语法:

std::pair<auto, auto> f() { return std::pair(1, 2); }
~~~~~~~~~~~~~~~~~~~~~

是原始概念 TS 的一部分,但未包含在作为 C++20 一部分的概念提案中。因此,C++20 中唯一的占位符类型是auto(及其变体,如auto**(、decltype(auto)和约束占位符(Concept auto及其变体(。这种嵌套占位符类型非常有用,但不是 C++20 的一部分,因此函数声明格式不正确。

现在,gcc 允许它,因为 gcc 实现了概念 TS,我猜他们决定保留这个功能。 clang 从未实现过 TS,所以它没有。

无论哪种方式,这:

std::pair<auto, auto> f() { return {1, 2}; }

总是格式不正确。语法的含义是我们推断返回类型,然后要求它与某些类型的pair<T, U>匹配TU.我们基本上是在尝试调用发明的函数:

template <typename T, typename U>
void __f(std::pair<T, U>);
__f({1, 2}); // this must succeed

但是你不能从{1, 2}推断出一个类型 - 一个大括号的初始化列表没有类型。也许这是应该探索的东西(因为至少在这样的简单情况下很容易理解(,但它从未被允许过。因此,无论哪种方式,拒绝它都是正确的。

最后:

GCC 9.2似乎认为std::pair<auto, auto>是一个int。这怎么解释呢?

出于某种原因(可能是由于我们的 C 遗留与隐式int(,当 gcc 无法识别或理解类型时,它只是使用int作为错误消息中的占位符。这非常令人困惑,因为显然是 gcc 提出了int而不是源代码。但事实就是如此。

最新更新