Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/apache-flex/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ typedef名称与可变模板参数名称一致时发生GCC错误_C++_C++11_Gcc_Compiler Errors_Variadic Templates - Fatal编程技术网

C++ typedef名称与可变模板参数名称一致时发生GCC错误

C++ typedef名称与可变模板参数名称一致时发生GCC错误,c++,c++11,gcc,compiler-errors,variadic-templates,C++,C++11,Gcc,Compiler Errors,Variadic Templates,我无意中发现了typedef和可变模板参数之间的一种奇怪的交互作用,我想了解这种交互作用。以下代码使用clang编译,但使用GCC时出现错误: template<typename T> // no error if this is not a template struct Traits; #pragma GCC diagnostic ignored "-Wunused-parameter" template<typename ...args> void functio

我无意中发现了
typedef
和可变模板参数之间的一种奇怪的交互作用,我想了解这种交互作用。以下代码使用clang编译,但使用GCC时出现错误:

template<typename T> // no error if this is not a template
struct Traits;

#pragma GCC diagnostic ignored "-Wunused-parameter"
template<typename ...args>
void function(args... e) {}

template<typename T>
struct Caller {
    typedef typename Traits<T>::types traits_types; // no error if this is changed to a 'using' directive

    template<typename ...types> // no error if the pack is converted to a single parameter
    static void method(types... e) {
        function<traits_types>(e...);
    }
};
然后评估模板参数替换,此时它将最后出现的标记
types
视为未展开的参数包,并相应地产生错误

我已经用GCC 6.4.0、7.3.0、8.2.0、8.3.0、9.1.0和9.2.0以及几个旧版本对此进行了测试,所有版本的行为都是一致的

叮当声 然而,当我用叮当声编译它时,它工作得很好

$ clang++-8 -Wall -Wpedantic -Wextra -std=c++11 -c test.cpp
$
这似乎是它首先替换了参数pack
types
,然后处理名称
traits\u types

我在Clang6.0.0、7.0.1和8.0.1以及一些旧版本中都看到了这种行为

问题: 在标准C++11中,GCC给出的错误是正确的,还是代码有效?或者是未定义/实现定义/未指定

我查阅了很多资料,但没有找到任何能清楚说明这个问题的资料。我还检查了其他几个问题(,,等等),所有这些问题看起来都很相似,但据我所知,并不完全适用于这种情况


如果这实际上是一个编译器错误,那么在错误跟踪器中找到一个相关问题的链接,确认GCC(或clang,如果适用)没有正确处理这个问题,将很好地解决这个问题。

是的,这是一个错误。您所观察到的“它的行为就像GCC在特征类型的定义中第一次替代一样”,随后是以下表现:

资料来源:

struct A {
    using CommonName = char;
};

template <typename T, typename... CommonName>
struct B {
    using V = typename T::CommonName;
};

template struct B<A>;


Output:

<source>:7:37: error: parameter packs not expanded with '...':
    7 |     using V = typename T::CommonName;
      |                                     ^
<source>:7:37: note:         'CommonName'
Compiler returned: 1
结构A{ 使用CommonName=char; }; 模板 结构B{ 使用V=typename T::CommonName; }; 模板结构B; 输出: :7:37:错误:参数包未使用“…”展开: 7 |使用V=typename T::CommonName; | ^ :7:37:注意:“CommonName” 返回的编译器:1 被所有GCC版本拒绝。已被msvc的clang接受


GCC的行为就像您直接编写了
typename Traits::types
,然后它会因为依赖名称
types
与模板参数包的名称相同而混淆。您可以通过给包不同的名称来绕过它,但是在标准C++中,依赖名可以与包的名称相同。因为一个必须合格,而另一个不合格,所以不应该有歧义。

太棒了,谢谢!出于我自己的教育目的,你知道标准中是否有什么特别的东西可以证明这一点吗?@DavidZ-似乎是最中肯的。它基本上说“如果可以在那里放置一个常规模板参数,那么这是一个有效的模式”。嗯,当常规模板参数是嵌套名称时,它不会保留其作为模板参数的含义。因此,这群人也不应该这样做。
$ clang++-8 -Wall -Wpedantic -Wextra -std=c++11 -c test.cpp
$
struct A {
    using CommonName = char;
};

template <typename T, typename... CommonName>
struct B {
    using V = typename T::CommonName;
};

template struct B<A>;


Output:

<source>:7:37: error: parameter packs not expanded with '...':
    7 |     using V = typename T::CommonName;
      |                                     ^
<source>:7:37: note:         'CommonName'
Compiler returned: 1