使用g ++ 4.9.0打包扩展失败,但适用于clang ++ 3.4

时间:2014-05-01 20:33:59

标签: c++ templates c++11 variadic-templates

对于以下代码:

template <typename... Ts>
struct Set {};

template <typename T, typename... Ts>
using Tail = Set<Ts...>;

template <typename T, typename TS>
struct MemberOf;

template <typename T, typename... Ts>
struct MemberOf<T, Set<T, Ts...>> {
    static constexpr bool value = true;
};

template <typename T>
struct MemberOf<T, Set<>> {
    static constexpr bool value = false;
};

template <typename T, typename... Ts>
struct MemberOf<T, Set<Ts...>> {
    static constexpr bool value = false || MemberOf<T, Tail<Ts...>>::value;
};

g ++ 4.9.0给出:

ts.cpp:27:63: error: pack expansion argument for non-pack parameter 'T' of alias template 'template<class T, class ... Ts> using Tail = Set<Ts ...>'
     static constexpr bool value = false || MemberOf<T, Tail<Ts...>>::value;
                                                               ^
ts.cpp:4:11: note: declared here
 template <typename T, typename... Ts>
           ^
ts.cpp:27:66: error: template argument 2 is invalid
     static constexpr bool value = false || MemberOf<T, Tail<Ts...>>::value;
                                                                  ^

clang ++ 3.4编译它没有任何诊断。它对我来说看起来像一个g ++错误,但只是想确认一下。

ADDENDUM:所以,基于下面的好答案,问题似乎是pack参数必须与别名模板中的pack参数完全对应。换句话说:

template <typename T, typename... Ts>
using Tail = Set<Ts...>;

template <typename... Ts>
using Alias1 = Tail<Ts...>; // ERROR, Ts doesn't correspond directly to the pack in Tail.

template <typename... Ts>
using Alias2 = Tail<int, Ts...>; // Okay, now it does.

2 个答案:

答案 0 :(得分:5)

由于修复了以下错误,clang的新版本现在也会拒绝您的代码:

http://llvm.org/bugs/show_bug.cgi?id=18401

理查德史密斯对此修复的评论是:

  

通过实施当前提出的核心方向来修复断言   问题1430.不要让包扩展用作别名的参数   模板,除非相应的参数是参数包。

作为示例,引用的core defect包括与您的代码基本相同的代码:

template<class... x> class list{};
template<class a, class... b> using tail=list<b...>;
template <class...T> void f(tail<T...>);

int main() {
  f<int,int>({});
}

缺陷说明:

  

此示例的处理存在实现差异。

缺陷给出的早期示例是一个更困难的案例,似乎要求模板别名不像模板的透明别名。由于这个实现问题,委员会显然倾向于禁止以某种方式使用模板别名,并且编译器实现者似乎正在使用该解决方案。

所以我的理解是这个代码在编写的当前规范下是有效的,但是存在实现问题,委员会最终可能会禁止它。

答案 1 :(得分:1)

模板别名的使用应该是这样的,即别名可以在使用它的地方扩展。

定义

之后
template <typename T, typename... Ts>
using Tail = Set<Ts...>;

你使用

Tail<Ts...>

但这不能被涉及Set<...>的任何内容取代。

(我必须承认,我很难找到支持这种解释的参考资料,因此我不确定这是否符合标准规定,或仅仅是编制者实施的内容。)