将std :: tuple转换为模板参数包 [英] Translating a std::tuple into a template parameter pack

查看:167
本文介绍了将std :: tuple转换为模板参数包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个

  typedef std :: tuple< A,B&元组类型; 

,并希望使用类别列表
作为模板 p>

假设我有:

  template< typename ... args> 
std :: tuple< args ...> parse(std :: istream& stream){
return std :: make_tuple(args(stream)...);
}

,我可以成功地使用它:

  auto my_tuple = parse< A,B>(ifs); 

可以避免必须指定类列表A, p>

  typedef std :: tuple< A,B&元组类型; 

其中列表A,B已存在?


$ b b

示例:

  #include< cstdlib& // EXIT_SUCCESS,EXIT_FAILURE 
#include< iostream> // std :: cerr
#include< fstream> // std :: ifstream
#include< tuple> // std :: tuple

class A {
public:
A(std :: istream&); // May throw FooBaarException
};

B类{
public:
B(std :: istream&); // May throw FooBaarException
};

template< typename ... args>
std :: tuple< args ...> parse(std :: istream& stream){
return std :: make_tuple(args(stream)...);
}

int main(){
std :: ifstream ifs;
ifs.exceptions(ifstream :: eofbit | ifstream :: failbit | ifstream :: badbit);
int res = EXIT_FAILURE;
try {
ifs.open(/ some / file / path,std :: ios :: in | std :: ios :: binary);
auto my_tuple = parse< A,B>(ifs); // my_tuple的类型为std :: tuple< A,B>
/ *这里做一些有趣的事情my_tuple * /
res = EXIT_SUCCESS;
} catch(ifstream :: failure e){
std :: cerr<< error:打开或读取文件failed\\\
;
} catch(FooBaarException e){
std :: cerr<< error:parsing in a constructor failed\\\
;
}
return res;
}


解决方案

似乎是你想要专门化的功能模板 parse 为特殊情况下,当模板参数是 std :: tuple 。不幸的是,这种类型的专业化是不可能与功能模板。



但是,类模板是可能的。



因此,作为第一步,您可以将 parse 定义为 struct 的静态函数, :

 使用std :: istream; 
using std :: tuple;
using std :: make_tuple;

struct A {A(const istream&){}};
struct B {B(const istream&){}};

template< typename ... Args>
struct parser
{
/ *你的原始函数,现在在一个struct。
我使用直接元组构造和
初始化列表来绕过
的建议问题,在注释
中提到你的问题。 * /
static tuple< Args ...> parse(const istream& strm)
{return tuple< Args ...> {Args(strm)...}; }
};

template< typename ... Args>
struct parser< tuple< Args ...>>
{
/ *专用于元组。 * /
static tuple< Args ...> parse(const istream& strm)
{return parser< Args ...> :: parse(strm); }
};

然后,您可以以所需的方式调用它:

  int main()
{
typedef tuple< A,B& tuple_type;
auto tup = parser< tuple_type> :: parse(std :: cin);
return 0;
}

第二步,你可以定义一个函数模板对于正确的结构特殊化的参数:

  template< typename ... Args> 
auto parse(const istream& strm) - > decltype(parser {return parser< Args ...> :: parse(strm); }

现在你可以按照你想要的方式使用它:

  int main()
{
typedef tuple< A,B& tuple_type;
auto tup = parse< tuple_type>(std :: cin);
return 0;
}

(您仍然可以以旧方式使用它: auto tup = parse< A,B>(std :: cin)。)





$ b b

注释。如在parser :: parse()的注释中所提到的,我使用直接元组构造而不是 make_tuple 来避免构建元组元素的顺序的问题。这不是与你的问题直接相关,但是一件好事。请参见如何避免未定义的执行顺序使用std :: make_tuple 时的构造函数。


I have a

typedef std::tuple<A, B> TupleType;

and would like to use the list of classes for a "template".

Suppose I have:

template<typename... args>
std::tuple<args...> parse(std::istream &stream) {
  return std::make_tuple(args(stream)...);
}

and that I can successfully use it with:

auto my_tuple = parse<A, B>(ifs);

is it possible to avoid having to specify the class list A,B if I already have a

typedef std::tuple<A,B> TupleType;

where the list A,B is already present?

an example:

#include <cstdlib>  // EXIT_SUCCESS, EXIT_FAILURE
#include <iostream> // std::cerr
#include <fstream>  // std::ifstream
#include <tuple>    // std::tuple

class A {
public:
  A(std::istream &);  // May throw FooBaarException 
};

class B {
public:
  B(std::istream &); // May throw FooBaarException 
};

template<typename... args>
std::tuple<args...> parse(std::istream &stream) {
  return std::make_tuple(args(stream)...);
}

int main() {
  std::ifstream ifs;
  ifs.exceptions(ifstream::eofbit | ifstream::failbit | ifstream::badbit);
  int res = EXIT_FAILURE;
  try {
    ifs.open("/some/file/path", std::ios::in | std::ios::binary);
    auto my_tuple = parse<A, B>(ifs); // my_tuple is of the type std::tuple<A,B>
    /* Here do something interesting with my_tuple */ 
    res = EXIT_SUCCESS;
  } catch (ifstream::failure e) {
    std::cerr << "error: opening or reading file failed\n";
  } catch (FooBaarException e) {
    std::cerr << "error: parsing in a constructor failed\n";
  }
  return res;
}

解决方案

The underlying problem in your situation seems to be that you'd like to specialize the function template parse for the special case when the template argument is a std::tuple. Unfortunately, this kind of specialization isn't possible with function templates.

However, it is possible with class templates.

So, as a first step, you could define parse as a static function of a struct, like this:

using std::istream;
using std::tuple;
using std::make_tuple;

struct A { A(const istream &) {} };
struct B { B(const istream &) {} };

template <typename... Args>
struct parser
{
  /* Your original function, now inside a struct.
     I'm using direct tuple construction and an
     initializer list to circumvent the order-of-
     construction problem mentioned in the comment
     to your question. */
  static tuple<Args...> parse(const istream &strm)
  { return tuple<Args...> {Args(strm)...}; }
};

template <typename... Args>
struct parser<tuple<Args...>>
{
  /* Specialized for tuple. */
  static tuple<Args...> parse(const istream &strm)
  { return parser<Args...>::parse(strm); }
};

You can then call it in the desired way:

int main()
{
  typedef tuple<A,B> tuple_type;
  auto tup = parser<tuple_type>::parse(std::cin);
  return 0;
}

As a second step, you can define a function template (again) which passes the arguments on to the right specialization of the struct:

template <typename... Args>
auto parse(const istream &strm) -> decltype(parser<Args...>::parse(strm))
{ return parser<Args...>::parse(strm); }

And now you can use it in exactly the way you wanted:

int main()
{
  typedef tuple<A,B> tuple_type;
  auto tup = parse<tuple_type>(std::cin);
  return 0;
}

(And you can still use it in the old way, too: auto tup = parse<A,B>(std::cin).)


Remark. As mentioned in the comment to parser::parse(), I used direct tuple construction instead of make_tuple to avoid problems with the order of construction of the tuple elements. This is not directly related to your question, but a good thing to do. See how to avoid undefined execution order for the constructors when using std::make_tuple.

这篇关于将std :: tuple转换为模板参数包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆