当std :: make_tuple是r值引用

时间:2018-03-22 02:34:36

标签: c++ c++11 templates template-meta-programming

我正在尝试为练习制作自己的tuple实施方案。我试图将std::string作为rvalue传递给我的元组。但是,我无法获取编译代码,我想知道如何解决这个问题。我理解它会衰减到char * const,并将其替换为我的模板参数,但是当使用std::make_tuple(Args&&...)的标准库版本尝试类似的代码时,rvalue reference没有问题。所以我很好奇我在实现中缺少的内容以及如何解决它。为了深入理解,将理解详细说明。

的main.cpp

int main()
{
  //Tuple<int, int> int_tuple = custom_make_tuple(1, 2);
  int a = 1;
  int b = 1;
  std::string Testing = "testing";

  Tuple<int, int, char, std::string> t1 = makeTuple(1, b, 'c', "test"); //Fails to compile
  Tuple<int, int, char, std::string> t1 = makeTuple(1, b, 'c', Testing); //OK
  std::tuple<std::string> test = std::make_tuple("test"); //OK

  return 0;
}

tuple.h

template<typename... Types>
class Tuple;

// recursive case:
template<typename Head, typename... Tail>
class Tuple<Head, Tail...>
{
private:
  Head head;
  Tuple<Tail...> tail;
public:
  constexpr Tuple() {
  }

  template<typename FHead, typename... FTail>
  constexpr Tuple(FHead && head, FTail &&... tail)
    : head(std::forward<FHead>(head)), tail(std::forward<FTail>(tail)...) {}

  constexpr Head& GetHead() { return head; }
  constexpr Head const& GetHead() const { return head; }
  constexpr Tuple<Tail...>& GetTail() { return tail; }
  constexpr Tuple<Tail...> const& GetTail() const { return tail; }
};

// basis case:
template<>
class Tuple<> {};

template<typename... Eles>
constexpr auto makeTuple(Eles&&... elems)
{
  return Tuple<std::decay_t<Eles>...>(std::forward<Eles>(elems)...);
}

1 个答案:

答案 0 :(得分:1)

makeTuple(1, b, 'c', "test")返回Tuple<int, int, char, const char*>。然后,您尝试从该元组复制构造Tuple<int, int, char, std::string>,这不起作用,因为Tuple<int, int, char, std::string>的构造函数需要int类型的参数,{{1 },intchar,而不是std::string

您需要添加将接受元组的转换构造函数,并将包含的对象转换为您需要的类型:

Tuple<int, int, char, const char*>

Live Demo

请注意,template <typename... Types> friend class Tuple; template<typename FHead, typename... FTail, std::enable_if_t<sizeof...(Tail) + 1 == sizeof...(FTail) + 1>* = nullptr> constexpr Tuple(const Tuple<FHead, FTail...>& o) : head(o.head), tail(o.tail) {} template<typename FHead, typename... FTail, std::enable_if_t<sizeof...(Tail) + 1 == sizeof...(FTail) + 1>* = nullptr> constexpr Tuple(Tuple<FHead, FTail...>&& o) : head(std::move(o.head)), tail(std::move(o.tail)) {} 参数的存在是为了避免在您实际尝试创建包含单个std::enable_if_t的{​​{1}}时选择转换构造函数。