【问题标题】:Virtual template design虚拟模板设计
【发布时间】:2015-12-21 01:28:47
【问题描述】:

为了使用一个简化的示例,让我们考虑一些动物吃食物列表中的某些项目。食物列表针对不同情况有很多不同的迭代器。

class contains_fish
{
  public:
    bool operator () (const Food& food) const;
};
class is_vegetarian
{
  public:
    bool operator () (const Food& food) const;
};
class FoodList
{
  private:
    std::vector<Food> foodItems;
  public:
    typedef std::vector<Food>::iterator iterator;
    typedef std::vector<Food>::const_iterator const_iterator;
    typedef std::vector<Food>::reverse_iterator reverse_iterator;
    typedef std::vector<Food>::const_reverse_iterator const_reverse_iterator;
    typedef boost::filter_iterator<contains_fish,FoodList::iterator> fish_iterator;
    typedef boost::filter_iterator<contains_fish,FoodList::const_iterator> fish_const_iterator;
    typedef boost::filter_iterator<contains_fish,FoodList::reverse_iterator> fish_reverse_iterator;
    typedef boost::filter_iterator<contains_fish,FoodList::const_reverse_iterator> fish_const_reverse_iterator;
    typedef boost::filter_iterator<is_vegetarian,FoodList::iterator> vegetarian_iterator;
    typedef boost::filter_iterator<is_vegetarian,FoodList::const_iterator> vegetarian_const_iterator;
    typedef boost::filter_iterator<is_vegetarian,FoodList::reverse_iterator> vegetarian_reverse_iterator;
    typedef boost::filter_iterator<is_vegetarian,FoodList::const_reverse_iterator> vegetarian_const_reverse_iterator;
    //...
    //... with corresponding begin/end functions :
    FoodList::iterator begin() { return this->foodItems.begin(); }
    FoodList::const_iterator begin() const { return this->foodItems.begin(); }
    //...
    FoodList::vegetarian_const_reverse_iterator begin_vegetarian_const_reverse() const { return boost::make_filter_iterator<is_vegetarian>(this->foodItems.rbegin(), this->foodItems.rend()); }
};

现在我想通过食物列表上的迭代器为每只动物提供食物(一个虚函数)。像这样的代码(由于虚拟模板功能而无法工作):

class Animal
{
  public:
    virtual ~Animal() {}
    template <typename FoodListIterator>
    virtual void eat(FoodListIterator begin, FoodListIterator end) = 0;
};

class Dog : public Animal
{
  public:
    virtual ~Dog() {}
    template <typename FoodListIterator>
    virtual void eat(FoodListIterator begin, FoodListIterator end)
    {
      if(begin == end)
        std::cout << "Sad day ! Nothing for me..." << std::endl;
      else
      {
        std::cout << "I'm a dog and I'm going to eat :" << std::endl;
        for(FoodListIterator it = begin; it != end; ++it)
          std::cout << it->toString() << std::endl;
      }
    }
};

void give_fish(std::vector<Animal*>& animals, const FoodList& food_list)
{
  for(unsigned long int i = 0; i < animals.size(); ++i)
    animals[i]->eat(food_list.fish_begin(), food_list.fish_end());
}

我有太多不同的迭代器来为每个签名实现一个虚函数。

如果没有 C++11,我怎样才能优雅地做到这一点?如果有帮助,我知道符合条件的类型列表(FoodList 中描述的迭代器列表)。

【问题讨论】:

  • 既然你已经在使用 Boost,你应该可以使用 Boost 的any_range 或者只是它附带的any_iterator
  • 作为一般规则,不要将编译时多态性(模板)与运行时多态性(虚拟调用)混合。他们在一起玩得不好。
  • @Angew : 如果我很了解这个工具,我可以使用 boost::range_detail::any_iterator&lt;Food,Something&gt; 代替我的模板类型 FoodListIterator 吗?但我不太明白我必须使用什么作为第二种模板类型......:-/

标签: c++ templates virtual c++98


【解决方案1】:

您可以重新组织您的界面,使每个Animal 虚拟地输入一个Food,而非虚拟地输入一系列Foods:

class Animal
{
  public:
    virtual ~Animal() {}
    virtual void eat(Food& ) = 0; // or Food const&

    template <typename Iterator>
    void eat(Iterator begin, Iterator end) {
        for (; begin != end; ++begin) {
            eat(*begin);
        }
    }
};

如果你真的需要整个范围,你可以使用类似boost::any_range:

class Animal
{
public:
    using FoodRange = boost::any_range<Food, boost::forward_traversal_tag,
                                       Food&, std::ptrdiff_t>;

    virtual ~Animal() {}
    virtual void eat(FoodRange ) = 0;

    template <typename Iterator>
    void eat(Iterator begin, Iterator end) {
        eat(FoodRange{begin, end});
    }
};    

【讨论】:

  • 这不是一个真正的解决方案,因为我的算法使用有关范围内所有元素的全局信息。
  • @Caduchon 我...不知道这是什么意思。
  • 狗数自己要吃的东西是不行的,小于5就加评论;或者猫在吃之前检查它是否有特定的标准。虚拟吃功能需要所有元素来完成这项工作。
  • @Caduchon 那么你真的想要any_range
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-10
  • 2017-06-10
  • 2021-12-24
  • 2014-06-08
相关资源
最近更新 更多