Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/124.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;用于以通用方式返回序列的API_C++_Api_Generics_Sequences - Fatal编程技术网

C++ C++;用于以通用方式返回序列的API

C++ C++;用于以通用方式返回序列的API,c++,api,generics,sequences,C++,Api,Generics,Sequences,如果我正在编写一个库,并且我有一个需要返回一系列值的函数,我可以执行以下操作: std::vector<int> get_sequence(); template <typename T> void get_sequence(T & p_aInt) { p_aInt.push_back(25) ; // Or whatever you need to add } 这要求T_插入器是一个插入迭代器(例如,使用std::back_插入器(my_vector

如果我正在编写一个库,并且我有一个需要返回一系列值的函数,我可以执行以下操作:

std::vector<int> get_sequence();
template <typename T>
void get_sequence(T & p_aInt)
{
    p_aInt.push_back(25) ; // Or whatever you need to add
}
这要求T_插入器是一个插入迭代器(例如,使用
std::back_插入器(my_vector)
创建),但这似乎太容易被误用,因为编译器很乐意接受非插入迭代器,但在运行时会表现不正确

那么,设计返回任意长度序列的通用接口是否有最佳实践呢?

std::list
稍微好一点,我想。请注意,这不需要额外复制列表中的数据,因为它只是被复制的指针

这完全取决于你的消费者。如果你可以把它们看作C++开发人员,那么就给他们一个<代码> STD< /Cord>容器类,我说。 我唯一想到的另一件事是你会这么做:

void get_sequence(std::tr1::function<void(int)> f);
void get_序列(std::tr1::函数f);

然后调用方可以使用
std::tr1::bind
使您的
get\u序列
函数调用他们想要的对象(或不想要的对象)上的任何函数。您只需为正在创建的每个元素不断调用
f

您可以执行以下操作

template<typename container>
container get_sequence();

template void get_sequence(T_Container & container)
{
  //...
  container.assign(iter1, iter2);
  //...
}
template <typename OutputIter>
void generate_sequence(OutputIter out)
{
    //...
    while (...) { *out = ...; ++out; }
}
struct sequence_generator
{
    bool has_next() { ... }
    your_type next() { mutate_state(); return next_value; }

private:
    // some state
};
模板
容器get_序列();

并要求所提供的容器类型符合一些标准接口(比如让一个成员push_back,或者reserve,以便您的接口用户可以使用vector/deque/list)。

为什么您需要独立于容器的接口?ScottMeyers在他的“有效STL”中给出了一个很好的理由,不管诱惑有多大,都不要尝试使代码容器独立。基本上,容器的用途是完全不同的:您可能不想将输出存储在map或set中(它们不是interval容器),所以只剩下vector、list和deque,为什么希望在需要list的地方使用vector,反之亦然?它们是完全不同的,使用其中一个的所有特性比同时使用这两个特性效果更好。好吧,想想看“有效的STL”:它值得你花时间。

如果你对你的容器有所了解,你可以考虑做一些类似

的事情。
template<typename container>
container get_sequence();

template void get_sequence(T_Container & container)
{
  //...
  container.assign(iter1, iter2);
  //...
}
template <typename OutputIter>
void generate_sequence(OutputIter out)
{
    //...
    while (...) { *out = ...; ++out; }
}
struct sequence_generator
{
    bool has_next() { ... }
    your_type next() { mutate_state(); return next_value; }

private:
    // some state
};
或许


template void get_sequence(T_Container & container)
{
  //...
  container.resize(size);
  //use push_back or whatever
  //...
}
或者甚至控制你的策略,比如


class AssignStrategy // for stl
{
public:
  template
  void fill(T_Container & container, T_Container::iterator it1, T_Container::iterator it2){
    container.assign(it1, it2);
  }
};

class ReserveStrategy // for vectors and stuff
{
public:
  template
  void fill(T_Container & container, T_Container::iterator it1, T_Container::iterator it2){
    container.reserve(it2 - it1);
    while(it1 != it2)
      container.push_back(*it1++);
  }
};


template 
void get_sequence(T_Container & container)
{
  //...
  T_FillStrategy::fill(container, iter1, iter2);
  //...
}

您可以使用iterator\u特性对迭代器类型进行静态分派

大概是这样的:

template<T_insertIter> get_sequence(T_insertIter inserter)
{
   return get_sequence(inserter, typename iterator_traits<Iterator>::iterator_category());
}

template<T_insertIter> get_sequence(T_insertIter inserter, input_iterator_tag);
模板获取\u序列(T\u插入器插入器)
{
返回get_序列(inserter,typename迭代器_traits::迭代器_category());
}
模板get_序列(T_插入器插入器、输入_迭代器_标记);

让get\u sequence返回一个(自定义)
前向迭代器
类,该类按需生成序列。(如果适合您的序列,它也可以是一种更高级的迭代器类型,如
双向迭代器

然后用户可以将序列复制到他们想要的任何容器类型中。或者,它们可以直接在迭代器上循环,完全跳过容器

您将需要某种类型的结束迭代器。如果不知道您是如何生成序列的,就很难说您应该如何实现它。一种方法是让迭代器类具有返回结束迭代器的静态成员函数,如:

static const my_itr& end() { static const my_itr e(...); return e; };
其中,
表示创建结束迭代器(可能使用私有构造函数)所需的任何参数。然后,您的循环将如下所示:

for (my_itr i = get_sequence(); i != my_itr::end(); ++i) { ... }
下面是一个生成连续整数序列的前向迭代器类的简单示例。显然,可以很容易地将其转换为双向或随机访问迭代器,但我希望保持示例的小型化

#include <iterator>

class integer_sequence_itr
  : public std::iterator<std::forward_iterator_tag, int>
{
 private:
  int i;

 public:
  explicit integer_sequence_itr(int start) : i(start) {};

  const int& operator*()  const { return i; };
  const int* operator->() const { return &i; };

  integer_sequence_itr& operator++() { ++i; return *this; };
  integer_sequence_itr  operator++(int)
    { integer_sequence_itr copy(*this); ++i; return copy; };

  inline bool operator==(const integer_sequence_itr& rhs) const
    { return i == rhs.i; };

  inline bool operator!=(const integer_sequence_itr& rhs) const
    { return i != rhs.i; };
}; // end integer_sequence_itr

//Example:  Print the integers from 1 to 10.
#include <iostream>

int main()
{
  const integer_sequence_itr stop(11);

  for (integer_sequence_itr i(1); i != stop; ++i)
    std::cout << *i << std::endl;

  return 0;
} // end main
#包括
类整数\u序列\u itr
:public std::迭代器
{
私人:
int i;
公众:
显式整数序列:i(start){};
常量int&运算符*()常量{return i;};
常量int*运算符->()常量{return&i;};
整数_序列_itr&operator++(){++i;返回*this;};
整数序列itr运算符++(int)
{integer_sequence_itr copy(*this);++i;return copy;};
内联布尔运算符==(常量整数\u序列\u itr&rhs)常量
{return i==rhs.i;};
内联布尔运算符!=(常量整数\u序列\u itr&rhs)常量
{return i!=rhs.i;};
}; // 结束整数\u序列\u itr
//示例:打印从1到10的整数。
#包括
int main()
{
常数整数序列停止(11);
对于(整数序列i(1);i!=stop;++i)

std::cout需要特别注意的一件事是,如果您所说的库是指DLL或类似的库,那么,如果库使用者(例如应用程序)是使用库本身以外的其他编译器构建的,则可能会出现问题


考虑这样一种情况,在您的示例中,您按值返回一个
std::vector
。然后,内存将在库的上下文中分配,但在应用程序的上下文中取消分配。两个不同的编译器可能会以不同的方式分配/取消分配,因此可能会发生严重破坏。

呃…只有我的两分钱,但是:

void get_sequence(std::vector<int> & p_aInt);
void get_序列(std::vector&p_aInt);
这将消除潜在的复制返回问题。 现在,如果您真的想避免使用容器,可以尝试以下方法:

std::vector<int> get_sequence();
template <typename T>
void get_sequence(T & p_aInt)
{
    p_aInt.push_back(25) ; // Or whatever you need to add
}
模板
无效获取序列(T&p维护)
{
p_aInt.push_back(25);//或任何需要添加的内容
}
这将只编译向量、列表和deque(以及类似的容器)。如果您想要一组可能的容器,代码将是:

template <typename T>
void get_sequence(T & p_aInt)
{
    p_aInt.insert(p_aInt.end(), 25) ; // Or whatever you need to add
}
模板
无效获取序列(T&p维护)
{
p_aInt.insert(p_aInt.end(),25);//或任何需要添加的内容
}

但正如其他帖子所说,您应该接受将接口限制为一种容器。

如果您已经为序列管理内存,您可以返回一对迭代器供调用方在for l中使用