如何创建自己的piecewise_construct构造函数?

时间:2016-05-14 17:01:05

标签: c++ c++11 c++14

这是我到目前为止以std::pair::pair(std::piecewise_construct_t, ...)样式实现自定义构造函数的示例:

#include <tuple>
#include <string>
#include <utility>
#include <iostream>

struct A {
  std::string m_a;
  std::string m_b;
  std::string m_c;

  A() = default;
  A(const A&) = default;
  A(A&&) = default;
  ~A() = default;

  template <typename T1, typename T2, typename T3>
  A(T1&& a, T2&& b, T3&& c) :
    m_a { std::forward<T1>(a) }, m_b { std::forward<T2>(b) }, m_c { std::forward<T3>(c) }
  { }

  template <typename... T1, typename... T2, typename... T3,
            std::size_t... I1, std::size_t... I2, std::size_t... I3>
  A(std::tuple<T1...> args1,
    std::tuple<T2...> args2,
    std::tuple<T3...> args3,
    std::integer_sequence<std::size_t, I1...>,
    std::integer_sequence<std::size_t, I2...>,
    std::integer_sequence<std::size_t, I3...>) :
    m_a { std::forward<T1>(std::get<I1>(args1))... },
    m_b { std::forward<T2>(std::get<I2>(args2))... },
    m_c { std::forward<T3>(std::get<I3>(args3))... }
  { }

  template <typename... T1, typename... T2, typename... T3>
  A(std::piecewise_construct_t,
    std::tuple<T1...> args1,
    std::tuple<T2...> args2,
    std::tuple<T3...> args3) :
    A { args1, args2, args3,
      std::make_index_sequence<sizeof...(T1)>{},
      std::make_index_sequence<sizeof...(T2)>{},
      std::make_index_sequence<sizeof...(T3)>{} }
  { }
};

int main() {
  A a { std::piecewise_construct,
      std::forward_as_tuple("abc"),
      std::forward_as_tuple(10, 'd'),
      std::forward_as_tuple("ef\0\0gh", 6)
      };
  std::cout << "m_a: " << a.m_a <<
    "\nm_b: " << a.m_b <<
    "\nm_c: " << a.m_c << '\n';
  return 0;
}

预期输出(如果通过cat -v传送):

m_a: abc
m_b: dddddddddd
m_c: ef^@^@gh

然而,gcc仍然给我错误,我无法解释,这似乎与std::tuple的内部实现有关:

/tmp/from_tuple.cpp: In instantiation of ‘A::A(std::piecewise_construct_t, std::tuple<_Elements ...>, std::tuple<_Elements ...>, std::tuple<_Tail ...>) [with T1 = {const char (&)[4]}; T2 = {int&&, char&&}; T3 = {const char (&)[7], int&&}]’:
/tmp/from_tuple.cpp:51:11:   required from here
/tmp/from_tuple.cpp:42:53: error: use of deleted function ‘constexpr std::tuple<_T1, _T2>::tuple(const std::tuple<_T1, _T2>&) [with _T1 = int&&; _T2 = char&&]’
           std::make_index_sequence<sizeof...(T3)>{} }
                                                     ^
In file included from /tmp/from_tuple.cpp:1:0:
/usr/include/c++/5/tuple:615:17: note: ‘constexpr std::tuple<_T1, _T2>::tuple(const std::tuple<_T1, _T2>&) [with _T1 = int&&; _T2 = char&&]’ is implicitly deleted because the default definition would be ill-formed:
       constexpr tuple(const tuple&) = default;
                 ^
/usr/include/c++/5/tuple:615:17: error: use of deleted function ‘constexpr std::_Tuple_impl<_Idx, _Head, _Tail ...>::_Tuple_impl(const std::_Tuple_impl<_Idx, _Head, _Tail ...>&) [with long unsigned int _Idx = 0ul; _Head = int&&; _Tail = {char&&}]’
/usr/include/c++/5/tuple:215:17: note: ‘constexpr std::_Tuple_impl<_Idx, _Head, _Tail ...>::_Tuple_impl(const std::_Tuple_impl<_Idx, _Head, _Tail ...>&) [with long unsigned int _Idx = 0ul; _Head = int&&; _Tail = {char&&}]’ is implicitly deleted because the default definition would be ill-formed:
       constexpr _Tuple_impl(const _Tuple_impl&) = default;
                 ^
/usr/include/c++/5/tuple:215:17: error: use of deleted function ‘constexpr std::_Tuple_impl<_Idx, _Head>::_Tuple_impl(const std::_Tuple_impl<_Idx, _Head>&) [with long unsigned int _Idx = 1ul; _Head = char&&]’
/usr/include/c++/5/tuple:364:17: note: ‘constexpr std::_Tuple_impl<_Idx, _Head>::_Tuple_impl(const std::_Tuple_impl<_Idx, _Head>&) [with long unsigned int _Idx = 1ul; _Head = char&&]’ is implicitly deleted because the default definition would be ill-formed:
       constexpr _Tuple_impl(const _Tuple_impl&) = default;
                 ^
/usr/include/c++/5/tuple:364:17: error: use of deleted function ‘constexpr std::_Head_base<_Idx, _Head, false>::_Head_base(const std::_Head_base<_Idx, _Head, false>&) [with long unsigned int _Idx = 1ul; _Head = char&&]’
/usr/include/c++/5/tuple:110:17: note: ‘constexpr std::_Head_base<_Idx, _Head, false>::_Head_base(const std::_Head_base<_Idx, _Head, false>&) [with long unsigned int _Idx = 1ul; _Head = char&&]’ is implicitly deleted because the default definition would be ill-formed:
       constexpr _Head_base(const _Head_base&) = default;
                 ^
/usr/include/c++/5/tuple:110:17: error: copying non-static data member ‘char&& std::_Head_base<1ul, char&&, false>::_M_head_impl’ of rvalue reference type
/usr/include/c++/5/tuple:215:17: error: use of deleted function ‘constexpr std::_Head_base<_Idx, _Head, false>::_Head_base(const std::_Head_base<_Idx, _Head, false>&) [with long unsigned int _Idx = 0ul; _Head = int&&]’
       constexpr _Tuple_impl(const _Tuple_impl&) = default;
                 ^
/usr/include/c++/5/tuple:110:17: note: ‘constexpr std::_Head_base<_Idx, _Head, false>::_Head_base(const std::_Head_base<_Idx, _Head, false>&) [with long unsigned int _Idx = 0ul; _Head = int&&]’ is implicitly deleted because the default definition would be ill-formed:
       constexpr _Head_base(const _Head_base&) = default;
                 ^
/usr/include/c++/5/tuple:110:17: error: copying non-static data member ‘int&& std::_Head_base<0ul, int&&, false>::_M_head_impl’ of rvalue reference type
/tmp/from_tuple.cpp:23:7: note:   initializing argument 2 of ‘A::A(std::tuple<_Elements ...>, std::tuple<_Elements ...>, std::tuple<_Tail ...>, std::integer_sequence<long unsigned int, I1 ...>, std::integer_sequence<long unsigned int, I2 ...>, std::integer_sequence<long unsigned int, I3 ...>) [with T1 = {const char (&)[4]}; T2 = {int&&, char&&}; T3 = {const char (&)[7], int&&}; long unsigned int ...I1 = {0ul}; long unsigned int ...I2 = {0ul, 1ul}; long unsigned int ...I3 = {0ul, 1ul}]’
       A(std::tuple<T1...> args1,
       ^
/tmp/from_tuple.cpp:42:53: error: use of deleted function ‘constexpr std::tuple<_T1, _T2>::tuple(const std::tuple<_T1, _T2>&) [with _T1 = const char (&)[7]; _T2 = int&&]’
           std::make_index_sequence<sizeof...(T3)>{} }
                                                     ^
In file included from /tmp/from_tuple.cpp:1:0:
/usr/include/c++/5/tuple:615:17: note: ‘constexpr std::tuple<_T1, _T2>::tuple(const std::tuple<_T1, _T2>&) [with _T1 = const char (&)[7]; _T2 = int&&]’ is implicitly deleted because the default definition would be ill-formed:
       constexpr tuple(const tuple&) = default;
                 ^
/usr/include/c++/5/tuple:615:17: error: use of deleted function ‘constexpr std::_Tuple_impl<_Idx, _Head, _Tail ...>::_Tuple_impl(const std::_Tuple_impl<_Idx, _Head, _Tail ...>&) [with long unsigned int _Idx = 0ul; _Head = const char (&)[7]; _Tail = {int&&}]’
/usr/include/c++/5/tuple:215:17: note: ‘constexpr std::_Tuple_impl<_Idx, _Head, _Tail ...>::_Tuple_impl(const std::_Tuple_impl<_Idx, _Head, _Tail ...>&) [with long unsigned int _Idx = 0ul; _Head = const char (&)[7]; _Tail = {int&&}]’ is implicitly deleted because the default definition would be ill-formed:
       constexpr _Tuple_impl(const _Tuple_impl&) = default;
                 ^
/usr/include/c++/5/tuple:215:17: error: use of deleted function ‘constexpr std::_Tuple_impl<_Idx, _Head>::_Tuple_impl(const std::_Tuple_impl<_Idx, _Head>&) [with long unsigned int _Idx = 1ul; _Head = int&&]’
/usr/include/c++/5/tuple:364:17: note: ‘constexpr std::_Tuple_impl<_Idx, _Head>::_Tuple_impl(const std::_Tuple_impl<_Idx, _Head>&) [with long unsigned int _Idx = 1ul; _Head = int&&]’ is implicitly deleted because the default definition would be ill-formed:
       constexpr _Tuple_impl(const _Tuple_impl&) = default;
                 ^
/usr/include/c++/5/tuple:364:17: error: use of deleted function ‘constexpr std::_Head_base<_Idx, _Head, false>::_Head_base(const std::_Head_base<_Idx, _Head, false>&) [with long unsigned int _Idx = 1ul; _Head = int&&]’
/usr/include/c++/5/tuple:110:17: note: ‘constexpr std::_Head_base<_Idx, _Head, false>::_Head_base(const std::_Head_base<_Idx, _Head, false>&) [with long unsigned int _Idx = 1ul; _Head = int&&]’ is implicitly deleted because the default definition would be ill-formed:
       constexpr _Head_base(const _Head_base&) = default;
                 ^
/usr/include/c++/5/tuple:110:17: error: copying non-static data member ‘int&& std::_Head_base<1ul, int&&, false>::_M_head_impl’ of rvalue reference type
/tmp/from_tuple.cpp:23:7: note:   initializing argument 3 of ‘A::A(std::tuple<_Elements ...>, std::tuple<_Elements ...>, std::tuple<_Tail ...>, std::integer_sequence<long unsigned int, I1 ...>, std::integer_sequence<long unsigned int, I2 ...>, std::integer_sequence<long unsigned int, I3 ...>) [with T1 = {const char (&)[4]}; T2 = {int&&, char&&}; T3 = {const char (&)[7], int&&}; long unsigned int ...I1 = {0ul}; long unsigned int ...I2 = {0ul, 1ul}; long unsigned int ...I3 = {0ul, 1ul}]’
       A(std::tuple<T1...> args1,
       ^

1 个答案:

答案 0 :(得分:1)

哎呀,看起来我只需要更多的耐心看一下错误信息。如果我只是查看第一个,它告诉我std::tuple<int&&, char&&>有一个隐式删除的复制构造函数,大概是因为rvalue-reference成员。因此,如果我更改过载,使用虚拟integer_sequence对象来获取tuple个引用,那么示例将进行编译。

但是,在第二个元素的情况下,看起来它使用initializer_list构造函数而不是预期的size_t, char构造函数。在同一个重载中从撑杆初始化器更改为旧式括号初始化器,修复了这个问题。

总的来说,用以下内容替换掉过载:

  template <typename... T1, typename... T2, typename... T3,
            std::size_t... I1, std::size_t... I2, std::size_t... I3>
  A(std::tuple<T1...>& args1,
    std::tuple<T2...>& args2,
    std::tuple<T3...>& args3,
    std::integer_sequence<std::size_t, I1...>,
    std::integer_sequence<std::size_t, I2...>,
    std::integer_sequence<std::size_t, I3...>) :
    m_a(std::forward<T1>(std::get<I1>(args1))...),
    m_b(std::forward<T2>(std::get<I2>(args2))...),
    m_c(std::forward<T3>(std::get<I3>(args3))...)
  { }
相关问题