Add*_*ddy 6 c++ constructor struct tuples
如果我有一个像这样的结构:
struct Thing
{
  int x;
  int y;
  bool a;
  bool b;
}
Run Code Online (Sandbox Code Playgroud)
然后我可以通过以下方式创建一个Thing对象:Thing t {1,2,true,false};.但是,如果我有一个元组,那么我正在做类似的事情:
std::tuple<int, int, bool, bool> info = std::make_tuple(1,2,true,false);
Thing t { std::get<0>(info), std::get<1>(info).. // and so on
Run Code Online (Sandbox Code Playgroud)
有一个更好的方法吗?
如果您使用的是 c++14,您可以使用std::index_sequence创建辅助函数和结构,如下所示:
#include <tuple>
#include <utility>
struct Thing
{
  int x;
  int y;
  bool a;
  bool b;
};
template <class Thi, class Tup, class I = std::make_index_sequence<std::tuple_size<Tup>::value>>
struct Creator;
template <class Thi, class Tup, size_t... Is>
struct Creator<Thi, Tup, std::index_sequence<Is...> > {
   static Thi create(const Tup &t) {
      return {std::get<Is>(t)...};
   }
};
template <class Thi, class Tup>
Thi create(const Tup &t) {
   return Creator<Thi, Tup>::create(t);
}
int main() {
   Thing thi = create<Thing>(std::make_tuple(1,2,true,false));
}
Run Code Online (Sandbox Code Playgroud)
以及没有附加类的版本(具有一个附加功能):
#include <tuple>
#include <utility>
struct Thing
{
  int x;
  int y;
  bool a;
  bool b;
};
template <class Thi, class Tup, size_t... Is>
Thi create_impl(const Tup &t, std::index_sequence<Is...>) {
   return {std::get<Is>(t)...};
}
template <class Thi, class Tup>
Thi create(const Tup &t) {
   return create_impl<Thi, Tup>(t, std::make_index_sequence<std::tuple_size<Tup>::value>{});
}
int main() {
   Thing thi = create<Thing>(std::make_tuple(1,2,true,false));
}
Run Code Online (Sandbox Code Playgroud)
这次又是一个棘手的版本,只有一个辅助函数:
#include <tuple>
#include <utility>
struct Thing
{
  int x;
  int y;
  bool a;
  bool b;
};
template <class R, class T, size_t... Is>
R create(const T &t, std::index_sequence<Is...> = {}) {
   if (std::tuple_size<T>::value == sizeof...(Is)) {
      return {std::get<Is>(t)...};
   }
   return create<R>(t, std::make_index_sequence<std::tuple_size<T>::value>{});
}
int main() {
   Thing thi = create<Thing>(std::make_tuple(1,2,true,false));
}
Run Code Online (Sandbox Code Playgroud)
        我们可以从元组样类型创建聚集(创建一个通用的工厂函数std::tuple,std::pair,std::array,和任意用户定义的元组就像一个结构化的绑定世界中的物体†):
template <class T, class Tuple, size_t... Is>
T construct_from_tuple(Tuple&& tuple, std::index_sequence<Is...> ) {
    return T{std::get<Is>(std::forward<Tuple>(tuple))...};
}
template <class T, class Tuple>
T construct_from_tuple(Tuple&& tuple) {
    return construct_from_tuple<T>(std::forward<Tuple>(tuple),
        std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>{}
        );
}
Run Code Online (Sandbox Code Playgroud)
在您的情况下将用作:
std::tuple<int, int, bool, bool> info = std::make_tuple(1,2,true,false);
Thing t = construct_from_tuple<Thing>(info); // or std::move(info)
Run Code Online (Sandbox Code Playgroud)
这样,Thing仍然可以是聚合(不必添加构造函数/赋值),我们的解决方案可以解决许多类型的问题.
作为一项改进,我们可以将SFINAE添加到两个重载中,以确保它们无法使用无效的元组类型进行调用.
†在接受分解如何工作的措辞之前,std::get<Is>可能需要将符合条件的呼叫更改为get<Is>具有特殊查找规则的非限定呼叫.目前,这是没有实际意义,因为它是2016年,我们没有结构化绑定.
更新:在C++ 17中,有std::make_from_tuple().
提供显式构造函数和赋值运算符:
struct Thing
{
  int x;
  int y;
  bool a;
  bool b;
  Thing() { }
  Thing( int x, int y, bool a, bool b ): x(x), y(y), a(a), b(b) { }
  Thing( const std::tuple <int, int, bool, bool> & t ) 
  {
    std::tie( x, y, a, b ) = t;
  }
  Thing& operator = ( const std::tuple <int, int, bool, bool> & t ) 
  {
    std::tie( x, y, a, b ) = t;
    return *this;
  }
};
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助。