首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >类型胡枝子名称与可变模板参数名称重合时的GCC错误

类型胡枝子名称与可变模板参数名称重合时的GCC错误
EN

Stack Overflow用户
提问于 2019-11-16 13:35:40
回答 1查看 91关注 0票数 2

我偶然发现了typedef和各种模板参数之间的奇怪交互,我想了解这些参数。下面的代码使用clang编译,但是使用GCC时出现了一个错误:

代码语言:javascript
复制
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...);
    }
};

GCC行为

当我与GCC一起编译(而不是链接)时,我在第14行中得到了一个错误:

代码语言:javascript
复制
$ g++-9.2.0 -Wall -Wpedantic -Wextra -std=c++11 -c test.cpp
test.cpp: In static member function ‘static void Caller<T>::method(types ...)’:
test.cpp:14:31: error: parameter packs not expanded with ‘...’:
   14 |         function<traits_types>(e...);
      |         ~~~~~~~~~~~~~~~~~~~~~~^~~~~~
test.cpp:14:31: note:         ‘types’
$

它的作用就好像GCC在traits_types的定义中第一个替代了,这将产生

代码语言:javascript
复制
template<typename ...types>
static void method(types... e) {
    function<typename Traits<T>::types>(e...);
}

然后计算模板参数替换,此时它将令牌types的最后一次出现视为未展开的参数包,并相应地生成一个错误。

我在GCC 6.4.0、7.3.0、8.2.0、8.3.0、9.1.0和9.2.0以及几个较早的版本中测试了这一点,它们的行为都是一致的。

clang行为

但是,当我用clang编译它时,它工作得很好。

代码语言:javascript
复制
$ clang++-8 -Wall -Wpedantic -Wextra -std=c++11 -c test.cpp
$

这似乎是它首先替代了参数pack types,然后处理名称traits_types

在clang 6.0.0、7.0.1和8.0.1以及几个较早的版本中,我看到了这种行为。

问题

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

我查看了CpPreence.com关于模板和类型防御的内容的大部分内容,但没有找到任何明确解决这个问题的方法。我还检查了其他几个问题(123.4.5等),据我所知,所有这些问题似乎都类似,但并不完全适用于这种情况。

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-11-16 14:17:19

是的是虫子。你所观察到的“它的作用就像GCC在traits_types定义中第一次替代”,然后是GCC虫90189的一种表现形式。

来源: 结构A{使用CommonName = char;};模板结构B{使用V= typename T::CommonName;};模板结构B;输出:7:37: error:参数包没有用‘.’展开的参数包,使用V= typename T::CommonName;\x^ :7:37:注意:'CommonName‘编译器返回:1 被GCC所有版本所拒绝。由clang,msvc接受。

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

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58891286

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档