【问题标题】:Is this a compiler bug or a programmer bug?这是编译器错误还是程序员错误?
【发布时间】:2012-04-08 08:13:06
【问题描述】:

我正在使用元组作为编译时间列表。在How can I have multiple parameter packs in a variadic template? 中,我用一些在 GCC 和 Clang 中都可以使用的代码回答了自己,但是由于我已经添加了(我认为是)完美转发,所以 Clang 不会编译。它抱怨As...as...std::forward<As>(as)... 中有不同的长度。当As...as... 的类型时,这怎么可能是真的?参数中是As&&... as

#include <iostream>
#include <tuple>

template < typename ... >
struct two_impl {};

// Base case
template < typename F,
           typename ...Bs >
struct two_impl < F, std::tuple <>, std::tuple< Bs... > >  {
  void operator()(F&& f, Bs&&... bs) {
    f(std::forward<Bs>(bs)...);
  }
};

// Recursive case
template < typename F,
           typename A,
           typename ...As,
           typename ...Bs >
struct two_impl < F, std::tuple< A, As... >, std::tuple< Bs...> >  {
  void operator()(F&& f, A&& a, As&&... as, Bs&&... bs) {
    auto impl = two_impl < F, std::tuple < As&&... >, std::tuple < Bs&&..., A&& > >();
    impl(std::forward<F>(f), std::forward<As>(as)..., std::forward<Bs>(bs)..., std::forward<A>(a));
  }
};

template < typename F, typename ...Ts >
void two(F&& f, Ts&& ...ts) {
  auto impl = two_impl< F, std::tuple < Ts... >, std::tuple <> >();
  impl(std::forward<F>(f), std::forward<Ts>(ts)...);
}

struct Test {
  void operator()(int i, float f, double d) {
    std::cout << i << std::endl << f << std::endl << d << std::endl;
  }
};

int main () {
  two(Test(), 1, 1.5f, 2.1);
}

clang -lstdc++ -std=c++0x multiple_parameter_packs.cpp编译

clang -lstdc++ -std=c++0x multiple_parameter_packs.cpp 
multiple_parameter_packs.cpp:24:50: error: pack expansion contains parameter packs 'As' and 'as' that have different
      lengths (1 vs. 2)
    impl(std::forward<F>(f), std::forward<As>(as)..., std::forward<Bs>(bs)..., std::forward<A>(a));
                                          ~~  ~~ ^
multiple_parameter_packs.cpp:24:5: note: in instantiation of member function 'two_impl<Test, std::tuple<float &&,
      double &&>, std::tuple<int &&> >::operator()' requested here
    impl(std::forward<F>(f), std::forward<As>(as)..., std::forward<Bs>(bs)..., std::forward<A>(a));
    ^
multiple_parameter_packs.cpp:31:3: note: in instantiation of member function 'two_impl<Test, std::tuple<int, float,
      double>, std::tuple<> >::operator()' requested here
  impl(std::forward<F>(f), std::forward<Ts>(ts)...);
  ^
multiple_parameter_packs.cpp:41:3: note: in instantiation of function template specialization
      'two<Test, int, float, double>' requested here
  two(Test(), 1, 1.5f, 2.1);
  ^
1 error generated.

Compilation exited abnormally with code 1 at Fri Mar 23 14:25:14

【问题讨论】:

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


【解决方案1】:

这似乎是旧版 Clang 中的错误。该代码适用于trunk Clang,无论是libstdc++还是libc++。

$ clang++ multiple_parameter_packs.cpp -std=c++11 -stdlib=libc++
$ ./a.out
1
1.5
2.1

【讨论】:

    【解决方案2】:

    我不认为这是:

    void operator()(F&& f, A&& a, As&&... as, Bs&&... bs)
    

    很有可能。

    参数包应该是最后一个参数,As&amp;&amp;... as 后面是另一个包。

    【讨论】:

    • 参数包应该放在最后,除非它们在另一个类型中(比如void foo(tuple&lt;Ts...&gt;,tuple&lt;Us...&gt;)),但不是必须的。如果不是,则无法自动推断出它们。当您明确指定它们时,模板参数列表中的第一个包似乎在此时获取所有剩余的模板参数。以后的包将是空的,如果有非包参数,那么模板将不起作用,因为不会有任何模板参数离开:template&lt;class... Ts,class U&gt; void f(); // f can never be instantiated
    • operator() 的函数参数在不可推导的上下文中。编译器已经绑定了例如 到 As... 在对包含 operator() 的结构进行推导期间。 As...不会吃掉Bs的剩余参数...因为它的arity已经被推断出来了。
    猜你喜欢
    • 2011-08-03
    • 1970-01-01
    • 1970-01-01
    • 2012-08-06
    • 2012-03-18
    • 1970-01-01
    • 2020-06-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多