【问题标题】:Tuple with Variadic Templates compile error带有可变参数模板的元组编译错误
【发布时间】:2018-07-31 08:21:32
【问题描述】:

我正在尝试使用自制的元组实现来学习可变参数模板。 有人可以向我解释为什么以下会导致编译错误吗?

namespace my
{
  // Template definition
  template <typename... Ts> struct tuple;

  template <typename T, typename... Ts>
  struct tuple<T, Ts...> : public tuple<Ts...>
  {
    tuple(T t, Ts... ts) : tuple<Ts...>(ts...), mVal(t) {}
    T mVal;
  };

  template <typename T>
  struct tuple<T>
  {
    tuple(T t) : mVal(t) {}
    T mVal;
  };


  // GetType at an index
  template <size_t i, typename... Ts> struct GetType {};

  template <size_t i, typename T, typename... Ts> 
  struct GetType<i, tuple<T,Ts...> > 
  {
    using Type = typename GetType<i-1, tuple<Ts...> >::Type;
  };

  template <typename T, typename... Ts>
  struct GetType<0, tuple<T,Ts...> >
  {
    using Type = T;
  };


  template <size_t i, typename... Ts>
  typename GetType<i,tuple<Ts...> >::Type Get(tuple<Ts...>& t);

  template <size_t i, typename T, typename... Ts>
  typename GetType<i,tuple<T,Ts...> >::Type Get(tuple<T,Ts...>& t)
  {
    return Get<i-1, tuple<Ts...> >(t);
  }

  template <typename T, typename... Ts>
  typename GetType<0,tuple<T,Ts...> >::Type Get(tuple<T,Ts...>& t)
  {
    return (static_cast<tuple<T, Ts...> >(t)).mVal;
  }  
}

int main()
{
  using myTuple = my::tuple<int, std::string, double, char>;

  // The following lines compile fine ....
  my::GetType<0,myTuple>::Type s0 = 437;
  my::GetType<1,myTuple>::Type s1 = std::string("Test string");
  my::GetType<2,myTuple>::Type s2 = 299.3243;
  my::GetType<3,myTuple>::Type s3 = 'Z';
  std::cout << s0 << " - " << s1 << " - " << s2 << " - " << s3 << std::endl;

  myTuple t(437, "This is the actual tuple string", 299.3243, '§');
  // This line does not compile !!! 
  int v = my::Get<0>(t);

  return 0;
}

我的意图是指示的行将使用特化,但查看编译错误很明显 value=0 的特化没有被使用。非常感谢您的帮助。

感谢您的宝贵时间..

c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(27): error C2039: 'Type': is not a member of 'my::GetType<18446744073709551614,my::tuple<>>'
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(27): note: see declaration of 'my::GetType<18446744073709551614,my::tuple<>>'
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(43): note: see reference to class template instantiation 'my::GetType<18446744073709551615,my::tuple<my::tuple<std::string,double,char>>>' being compiled
..\test.cpp(15): note: see reference to function template instantiation 'int my::Get<0,int,std::string,double,char>(my::tuple<int,std::string,double,char> &)' being compiled
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(27): error C2061: syntax error: identifier 'Type'
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(27): error C2238: unexpected token(s) preceding ';'
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(43): error C2672: 'Get': no matching overloaded function found
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(43): error C2770: invalid explicit template argument(s) for 'GetType<i,my::tuple<Ts...>>::Type my::Get(my::tuple<Ts...> &)'
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(38): note: see declaration of 'my::Get'

【问题讨论】:

  • 您的代码中没有Get 的特化。此外,您不能部分专门化一个函数。您可以将其包装为 struct 并使其成为 static 成员函数。
  • 谢谢。我在 Andrei Alexandrescu 的书中读到了它,但悲惨地忘记了。我希望不是 ammymore ..

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


【解决方案1】:

题外话介绍建议:如果您想使用语言重新创建您的标准工具版本(std::tuple,在这种情况下),请避免为您的结构、类、函数、类型提供相同的名称...

这样可以避免很多强烈的头痛。

建议结束。

正如 Daniel Langr 所观察到的,模板函数没有部分特化。

所以只用函数很难得到你想要的。

但是结构/类可以部分特化,所以我建议getH helper struct 写成如下

  template <std::size_t I, typename T, typename ... Ts>
  struct getH
   {
     static typename GetType<I, tuple<T, Ts...>>::Type
        func (tuple<T, Ts...> const & t)
      { return getH<I-1U, Ts...>::func(t); }
   };

  template <typename T, typename ... Ts>
  struct getH<0U, T, Ts...>
   {
     static T func (tuple<T, Ts...> const & t)
      { return t.mVal; }
   };

所以你的Get可以写成

  template <std::size_t I, typename ... Ts>
  typename GetType<I, tuple<Ts...>>::Type Get(tuple<Ts...> const & t)
   { return getH<I, Ts...>::func(t); };

如果可以使用 C++14,则返回类型可以简化为 auto 而不是 typename GetType&lt;I, tuple&lt;T, Ts...&gt;&gt;::Type

我观察到在您的代码中,您在不需要时使用了 static_cast

你在Get&lt;0&gt;使用过

  template <typename T, typename... Ts>
  typename GetType<0,tuple<T,Ts...> >::Type Get(tuple<T,Ts...>& t)
  {
    return (static_cast<tuple<T, Ts...> >(t)).mVal;
  }  

mVal 的类型为T(又名typename GetType&lt;0,tuple&lt;T,Ts...&gt; &gt;::Type)时

【讨论】:

  • 感谢您的详尽回答并纠正了static_cast的无用。我想我会把函数包装在结构中。
猜你喜欢
  • 1970-01-01
  • 2019-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多