考虑以下简单的代码:

template<typename ...types>
class myclass
{
    using payload_type = mylib::type_traits::type_or_tuple_t<types...>;

    template<typename... T>
    std::pair<bool, std::optional<payload_type>> try_push(T &&...data)
    {
        payload_type t;
        std::optional<decltype(t)> o;

        // this FAILS.
        //std::optional<payload_type> res;

        return {true, std::move(o)};
    }
};

上面,type_or_tuple助手简单地将可变参数包转换为以下类型:如果可变参数包是单一类型,则转换为单一类型;如果可变参数包是多种类型,T则转换为类型元组( )。tuple<types...>

Gcc (9/10/11) 无法编译此代码。具体来说,它似乎无法正确扩展payload_type上面的代码,这当然是通过帮助程序获取的类型type_or_tuple

g++-11 -O2 -std=c++17 -pedantic wtf.cpp -Wall -Wextra -D_POSIX_SOURCE=200809L -lrt -lmylib -lstdc++ -o q
wtf.cpp:27:70: error: parameter packs not expanded with ‘...’:
   27 |     std::pair<bool, std::optional<payload_type>> try_push(T &&...data)
      |                                                                      ^
wtf.cpp:27:70: note:         ‘T’

另请注意:

        payload_type t;
        std::optional<decltype(t)> o;

可以编译。但是注释掉的那一行不能。

另一方面,clang编译这个没有任何问题。

这是 gcc 中的错误还是语言使用不正确?有什么想法可以调整它以使其编译吗?

这是一个最小可重现的示例,其中包括的定义is_type_or_tuple

#include <iostream>
#include <type_traits>
#include<optional>
#include <tuple>

using namespace std;

template<typename... types>
struct type_or_tuple {
    using tup = std::tuple<types...>;
    using T = std::conditional_t<(std::tuple_size_v<tup> == 1),
                                 std::tuple_element_t<0, tup>,
                                 tup>;

    using is_tuple = std::conditional_t<(std::tuple_size_v<tup> > 1),
                                        std::true_type,
                                        std::false_type>;
};

template<typename... types>
using type_or_tuple_t = typename type_or_tuple<types...>::T;

//

template<typename ...types>
class myclass
{
    using payload_type = type_or_tuple_t<types...>;

    template<typename... T>
    std::pair<bool, std::optional<payload_type>> try_push(T &&...data)
    {
        payload_type t;
        std::optional<decltype(t)> o;

        // WILL NOT COMPILE!
        //std::optional<payload_type> res;

        return {true, std::move(o)};
    }
};

int main(int, const char **){
    myclass<unsigned> c;
}

3

  • 1
    请包含type_or_tuple定义。最好扩展您的问题以包含


    – 


  • @john 编辑后包含一个最小可重现的例子和 的定义type_or_tuple


    – 

  • 1
    一些别名应该有助于解决这个问题。godbolt.org/z/


    – 


最佳答案
1

这是一个错误。gcc 会混淆T成员函数模板中的 和T类型特征中的 。只需将 特征简单地更改为使用不同的名称而不是T,例如type,gcc 也会感到高兴:

template <class... types>
struct type_or_tuple {
    using tup = std::tuple<types...>;
    using type = std::conditional_t<sizeof...(types) == 1,
                                 std::tuple_element_t<0, tup>, tup>;
};

template <class... types>
using type_or_tuple_t = typename type_or_tuple<types...>::type;

和新的