std :: pair <自动,自动>返回类型

时间:2020-01-03 12:21:58

标签: c++ c++17 constexpr auto std-pair

我在auto中玩std::pair。在下面的代码中,函数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均未能对此进行编译。

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'

好的,c不喜欢任何一个。从第二条错误消息中,似乎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};
    /* ... */
}

clang 9.0和10.0

与以前相同,但有一个附加内容:

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

这里c仍然认为我们正在返回int

gcc 9.2

与以前相同。

gcc 10.0

有效!

我猜想某些功能还是必须实现的,或者在上述一种情况下,是否有一个编译器是正确的而另一个是错误的?我认为示例2应该有效。还是应该?

1 个答案:

答案 0 :(得分:23)

语法:

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

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

现在,gcc允许这样做,因为gcc实现了Concepts TS,我想他们决定保留此功能。 clang从未实现TS,所以没有实现。

无论哪种方式,

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

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

U

但是您不能从template <typename T, typename U> void __f(std::pair<T, U>); __f({1, 2}); // this must succeed 推导类型-大括号初始列表没有类型。也许这是应该探索的东西(因为至少在这样的简单情况下很容易理解),但是从来没有允许过。所以拒绝它是正确的。

最后:

gcc 9.2似乎认为{1, 2}std::pair<auto, auto>。怎么解释?

由于某种原因(可能是由于我们的C传统带有隐式int),当gcc无法识别或理解类型时,它仅将int用作错误消息中的占位符。这非常令人困惑,因为显然int附带的是gcc,而不是源代码。但这就是事实。

相关问题