首页 文章

gcc可以编译一个可变参数模板,而clang则不能

提问于
浏览
9

我正在阅读Leor Zolman先生提出的一些名为An Overview of C++11 and C++14的幻灯片 . 在第35页,他介绍了一种使用 decltype 进行求和运算的方法 .

struct Sum {
  template <typename T>
  static T sum(T n) {
    return n;
  }
  template <typename T, typename... Args>
  /// static T sum(T n, Args... rest) {
  static auto sum(T n, Args... rest) -> decltype(n + sum(rest...)) {
    return n + sum(rest...);
  }
};

当使用这个片段 Sum::sum(1, 2.3, 4, 5); clang-3.6(来自svn)无法用 -std=c++11 / -std=c++1y 编译它,但gcc-4.9成功 . 当然没有返回类型的类型推导都是编译,但是涉及类型转换并且无法获得预期的结果 .

那么这是否表示一个铿锵声,或者是因为gcc扩展(关于c 11或c 14)?

1 回答

  • 10

    Clang的行为是正确的 . 这是一个GCC错误(并且演示文稿中的声明也不正确) . §3.3.2[basic.scope.pdecl] / p1,6:

    1名称的声明点在其完整的声明者(第8条)之后和初始化者(如果有的话)之前,除非如下所述 . 6在声明类成员之后,可以在其类的范围内查找成员名称 .

    §3.3.7[basic.scope.class] / p1说

    以下规则描述了在类中声明的名称范围 . 1)在类中声明的名称的潜在范围不仅包括名称声明点后面的声明性区域,还包括所有函数体,默认参数,异常规范和非支撑或等于初始值的声明区域 . 该类中的静态数据成员(包括嵌套类中的这些内容) .

    trailing-return-types不在该列表中 .

    尾部返回类型是声明符的一部分(§8[dcl.decl] / p4):

    declarator:
        ptr-declarator
        noptr-declarator parameters-and-qualifiers trailing-return-type
    

    因此 sum 的可变版本不在其自己的trailing-return-type范围内,并且无法通过名称查找找到 .

    在C 14中,只需使用实际的返回类型推导(并省略尾随返回类型) . 在C 11中,您可以使用类模板和简单转发的函数模板:

    template<class T, class... Args>
    struct Sum {
        static auto sum(T n, Args... rest) -> decltype(n + Sum<Args...>::sum(rest...)) {
            return n + Sum<Args...>::sum(rest...);
        }
    };
    
    template<class T>
    struct Sum<T>{
        static T sum(T n) { return n; }
    };
    
    template<class T, class... Args>
    auto sum(T n, Args... rest) -> decltype(Sum<T, Args...>::sum(n, rest...)){
        return Sum<T, Args...>::sum(n, rest...);
    }
    

相关问题