Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.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++11 如何允许派生类通过虚方法返回类型上的任何迭代器?_C++11_Templates_Iterator_Return Value_Virtual Functions - Fatal编程技术网

C++11 如何允许派生类通过虚方法返回类型上的任何迭代器?

C++11 如何允许派生类通过虚方法返回类型上的任何迭代器?,c++11,templates,iterator,return-value,virtual-functions,C++11,Templates,Iterator,Return Value,Virtual Functions,我正在尝试编写一个小库,它允许用户实现某些行为,以便该库可以使用自己的底层数据结构。在这种特殊情况下(尽管我正在简化),我试图定义如下内容: class-LibraryClass{ 虚拟std::vector::const_迭代器intsBegin()const=0; 虚拟std::vector::const\u迭代器intsEnd()const=0; }; 换句话说,该库将接受使用任何派生类,从而允许它在整数向量上进行迭代。现在棘手的一点是:我不想强制使用向量。实际上,对我来说,任何对整数的

我正在尝试编写一个小库,它允许用户实现某些行为,以便该库可以使用自己的底层数据结构。在这种特殊情况下(尽管我正在简化),我试图定义如下内容:

class-LibraryClass{
虚拟std::vector::const_迭代器intsBegin()const=0;
虚拟std::vector::const\u迭代器intsEnd()const=0;
};
换句话说,该库将接受使用任何派生类,从而允许它在整数向量上进行迭代。现在棘手的一点是:我不想强制使用向量。实际上,对我来说,任何对整数的迭代器都是可以的,只要我能检测到它何时结束,并将其解引用为整数。以下是缺失的部分:

class-LibraryClass{
虚拟/*???*/intsBegin()常量=0;
虚拟/*???*/intsEnd()常量=0;
};
类用户类{
/*这应该是允许的,这里我用vector作为例子*/
std::vector::const_迭代器intsBegin()const;
std::vector::const_迭代器intsEnd()const;
};
现在,我知道如何通过模板获取方法参数,但我找不到在虚拟方法中将其作为返回值的方法,因为:

  • 迭代器是否为常量并不重要
  • 基类中不会有任何默认行为
  • 该机制不应受到继承的干扰:从
    int
    迭代器派生的类也应被接受为返回类型,因为它们满足要求。我不认为这是一个问题,因为及物性,但仍然是
  • 理想情况下,应该强制
    begin
    end
    方法在给定的派生类中具有相同的迭代器类型
  • 更理想的情况是,我希望避免将Boost用于
    enable\u if
    。该库是使用C++11编写的(至少我尝试过)

不如提供一个界面,让用户在不使用迭代器的情况下对数据执行任何操作

class LibraryClass {
public:
    virtual void visitInts(std::function<void(int)> f) = 0;
};

class UserClass : public LibraryClass {
public:
    void visitInts(std::function<void(int)> f) override {
        for (int data : m_vec)
            f(data);
    }
private:
    std::vector<int> m_vec;
};
class-LibraryClass{
公众:
虚空访问(标准::函数f)=0;
};
类用户类:公共图书馆类{
公众:
无效访问(标准::函数f)覆盖{
用于(整数数据:m_vec)
f(数据);
}
私人:
std::向量m_-vec;
};

例如,您失去了
std::binary_search
的功能,但您基本上具有相同的多功能性,无需在
用户类上强制使用特定的存储机制,您也可以将迭代器设置为虚拟类,例如(未经测试,并且明显不完整):

class-LibraryClass{
受保护的:
struct IteratorBase{//用户需要实现以下功能:
虚拟常量int&deref()常量=0;
虚空增量()=0;
虚空减量()=0;
//进一步的方法,例如比较和可能的克隆
};
虚拟std::unique_ptr intsBegin_uz()常量=0;
虚拟std::unique_ptr intsEnd_uz()常量=0;
公众:
类迭代器{
朋友班图书馆班;
标准:独特的国际热核聚变实验堆;
迭代器(std::unique_ptr&&iter):iter(std::move(iter){}
公众:
常量int&运算符*(){return iter->deref();}
常量迭代器和运算符++(){iter->increment();返回*this;}
//其他操作员。。。
};
迭代器intsBegin()常量{返回迭代器(intsBegin_());}
迭代器intsEnd()常量{返回迭代器(intsEnd();}
};

我不确定这是否值得付出努力,特别是因为即使对于非常简单的任务,也会有很多间接操作。我想你应该重新考虑一下你的设计…

任何迭代器都不难编写。如果你关心性能,这通常是个坏主意,因为每个操作都需要非零开销来完成类型ERA乌尔

假设您只需要为(:)
循环和“输入”迭代支持

namespace any_iteration_support {
  template<class VTable, class...Ts>
  VTable create() {
    VTable retval;
    VTable::template populate<Ts...>(retval);
    return retval;
  }
  template<class VTable, class...Ts>
  VTable const* get_vtable() {
    static VTable vtable = create<VTable, Ts...>();
    return &vtable;
  }
  struct input_iterator_vtable {
    void(*next)(void*) = 0;
    void(*dtor)(void*) = 0;
    void(*copy)(void* dest, void const* src) = 0;
    void*(*clone)(void const* src) = 0;
    bool(*equals)(void const* lhs, void const* rhs) = 0;
    template<class It>
    static void populate( input_iterator_vtable& vtable ) {
      vtable.next = [](void* ptr){
        auto& it = *static_cast<It*>(ptr);
        ++it;
      };
      vtable.dtor= [](void* ptr){
        auto* pit = static_cast<It*>(ptr);
        delete pit;
      };
      vtable.copy= [](void* dest, void const* src){
        auto& destit = *static_cast<It*>(dest);
        auto const& srcit = *static_cast<It const*>(src);
        destit = srcit;
      };
      vtable.clone= [](void const* src)->void*{
        auto const& srcit = *static_cast<It const*>(src);
        return new It(srcit);
      };
      vtable.equals= [](void const* lhs, void const* rhs)->bool{
        auto const& lhsit = *static_cast<It const*>(lhs);
        auto const& rhsit = *static_cast<It const*>(rhs);
        return lhsit == rhsit;
      };
    }
  };
  template<class T>
  struct any_input_iterator_vtable:input_iterator_vtable {
    T(*get)(void*) = 0;
    template<class It>
    static void populate(any_input_iterator_vtable& vtable) {
      input_iterator_vtable::populate<It>(vtable);
      vtable.get = [](void* ptr)->T{
        auto& it = *static_cast<It*>(ptr);
        return *it;
      };
    }
  };
}
template<class T>
struct any_input_iterator {
  any_iteration_support::any_input_iterator_vtable<T> const* vtable = 0;
  void* state = 0;
  template<class It,
    std::enable_if_t<!std::is_same<It, any_input_iterator>::value, int> =0
  >
  any_input_iterator( It it ):
    vtable(any_iteration_support::get_vtable<any_iteration_support::any_input_iterator_vtable<T>, It>()),
    state( new It(std::move(it)) )
  {}
  any_input_iterator(any_input_iterator&& o):
    vtable(o.vtable),
    state(o.state)
  {
    o.vtable = 0; o.state = 0;
  }
  any_input_iterator& operator=(any_input_iterator&& o) {
    using std::swap;
    swap(vtable, o.vtable);
    swap(state, o.state);
    return *this;
  }
  any_input_iterator(any_input_iterator const& o) {
    if (!o.vtable) return;
    state = o.vtable->clone(o.state);
    vtable = o.vtable;
  }
  any_input_iterator& operator=(any_input_iterator const& o) {
    if (!vtable && !o.vtable) return *this;
    if (vtable == o.vtable) {
      vtable->copy( state, o.state );
      return *this;
    }
    clear();
    if (!o.vtable) {
      return *this;
    }
    state = o.vtable->clone(o.state);
    vtable = o.vtable;
    return *this;
  }
  explicit operator bool()const { return vtable; }
  friend bool operator==(any_input_iterator const& lhs, any_input_iterator const& rhs) {
    if (!lhs && !rhs) return true;
    if (!lhs) return false;
    if (lhs.vtable != rhs.vtable) return false;
    return lhs.vtable->equals( lhs.state, rhs.state );
  }
  friend bool operator!=(any_input_iterator const& lhs, any_input_iterator const& rhs) {
    return !(lhs==rhs);
  }
  T operator*() const {
    return vtable->get( state );
  }
  any_input_iterator& operator++() {
    vtable->next(state);
    return *this;
  }
  any_input_iterator operator++(int) {
    auto retval = *this;
    ++*this;
    return retval;
  }
  ~any_input_iterator() { clear(); }
  void clear() {
      if (!vtable) return;
      auto dtor = vtable->dtor;
      auto s = state;
      state = 0;
      vtable = 0;
      dtor(s);
  }
  using reference = T;
  using value_type = typename std::remove_reference<T>::type;
  using iterator_category = std::input_iterator_tag;
};
当然,手动执行这种类型的擦除是乏味且容易出错的。我会使用类似类型擦除的方法,而不是使用上面提到的方法

有效的方法是使用span访问者

template<class T>
struct span {
  T* b = 0; T* e = 0;
  T* begin() const { return b; }
  T* end() const { return e; }
  bool empty() const { return begin()==end(); }
  std::size_t size() const { return end()-begin(); }
  span()=default;
  span(span const&)=default;
  span& operator=(span const&)=default;
  span(T* s, T* f):b(s),e(f) {};
  span(T* s, std::size_t length):span(s, s+length) {}
};
template<class T>
using span_visitor = std::function<void(span<T>)>;

class LibraryClass {
public:
  virtual void visitInts(span_visitor<int const> f) const = 0;
};

class VecImpl : public LibraryClass {
public:
  virtual void visitInts(span_visitor<int const> f) const override {
    f( {m_vec.data(), m_vec.size()} );
  };
private:
  std::vector<int> m_vec;
};
class SimpleListImpl : public LibraryClass {
public:
  virtual void visitInts(span_visitor<int const> f) const override {
    for (int i : m_list )
      f( {&i, 1} );
  };
private:
  std::list<int> m_list;
};
class FancyListImpl : public LibraryClass {
public:
  virtual void visitInts(span_visitor<int const> f) const override {
    std::size_t count = 0;
    std::array<int, 10> buffer;
    for (int i : m_list ) {
      buffer[count] = i;
      ++count;
      if (count == buffer.size()) {
        f({ buffer.data(), buffer.size()});
        count = 0;
      }
    }
    if (count) f({ buffer.data(), count});
  };
private:
  std::list<int> m_list;
};
模板
结构跨度{
T*b=0;T*e=0;
T*begin()常量{return b;}
T*end()常量{return e;}
bool empty()常量{return begin()==end();}
std::size_t size()常量{return end()-begin();}
span()=默认值;
span(span const&)=默认值;
span&运算符=(span常量&)=默认值;
span(T*s,T*f):b(s),e(f){};
span(T*s,std::size_T length):span(s,s+length){}
};
模板
使用span_visitor=std::函数;
班级图书馆班级{
公众:
虚拟无效访问量(span_访问者f)常数=0;
};
类VecImpl:公共图书馆类{
公众:
虚拟无效访问(span_visitor f)常量覆盖{
f({m_vec.data(),m_vec.size()});
};
私人:
std::向量m_-vec;
};
类SimpleListImpl:公共图书馆类{
公众:
虚拟无效访问(span_visitor f)常量覆盖{
用于(int i:m_列表)
f({&i,1});
};
私人:
std::列表m_列表;
};
类FancyListImpl:公共图书馆类{
公众:
虚拟无效访问(span_visitor f)常量覆盖{
标准::大小\u t计数=0;
std::数组缓冲区;
用于(int i:m_列表){
缓冲区[计数]=i;
++计数;
if(count==buffer.size()){
f({buffer.data(),buffer.size()});
计数=0;
}
}
if(count)f({buffer.data(),count});
};
私人:
std::列表m_列表;
};
你怎么吃

std::vector<int> get_ints_from(LibraryClass const& library) {
  std::vector<int> vec;
  library.visitInits([&](span<int const> ints){
    vec.append(ints.begin(), ints.end());
  });
  return vec;
}
std::vector get_ints_from(LibraryClass常量和库){
std::vec;
库访问([&](span ints){
append(ints.begin(),ints.end());
});
返回向量;
}
此接口将类型擦除移动到每个元素多次到每个元素一次

使用这种方法,您可以获得接近直接公开容器的性能,b
template<class T>
struct span {
  T* b = 0; T* e = 0;
  T* begin() const { return b; }
  T* end() const { return e; }
  bool empty() const { return begin()==end(); }
  std::size_t size() const { return end()-begin(); }
  span()=default;
  span(span const&)=default;
  span& operator=(span const&)=default;
  span(T* s, T* f):b(s),e(f) {};
  span(T* s, std::size_t length):span(s, s+length) {}
};
template<class T>
using span_visitor = std::function<void(span<T>)>;

class LibraryClass {
public:
  virtual void visitInts(span_visitor<int const> f) const = 0;
};

class VecImpl : public LibraryClass {
public:
  virtual void visitInts(span_visitor<int const> f) const override {
    f( {m_vec.data(), m_vec.size()} );
  };
private:
  std::vector<int> m_vec;
};
class SimpleListImpl : public LibraryClass {
public:
  virtual void visitInts(span_visitor<int const> f) const override {
    for (int i : m_list )
      f( {&i, 1} );
  };
private:
  std::list<int> m_list;
};
class FancyListImpl : public LibraryClass {
public:
  virtual void visitInts(span_visitor<int const> f) const override {
    std::size_t count = 0;
    std::array<int, 10> buffer;
    for (int i : m_list ) {
      buffer[count] = i;
      ++count;
      if (count == buffer.size()) {
        f({ buffer.data(), buffer.size()});
        count = 0;
      }
    }
    if (count) f({ buffer.data(), count});
  };
private:
  std::list<int> m_list;
};
std::vector<int> get_ints_from(LibraryClass const& library) {
  std::vector<int> vec;
  library.visitInits([&](span<int const> ints){
    vec.append(ints.begin(), ints.end());
  });
  return vec;
}