remove_if无法识别虚拟类中的operator()

时间:2014-04-30 13:04:16

标签: c++ polymorphism operator-overloading

我有对象的向量和要过滤的标准向量。受this post的Moo-Juice的启发,我写了一个代码:

#include <algorithm>
#include <string>
#include <memory>
#include <vector>

struct Token {

  char code;
   int val;

  Token(char c,int a) : code(c),val(a) {}
};

class FilterBase {
public:
  virtual bool operator()(const std::shared_ptr<Token> p) =0;
};

class ByCode : public FilterBase {
public:
  ByCode( char c) : code_(c) {}

  virtual bool operator()(const std::shared_ptr<Token> p) {
    return code_ == p->code;
  }

private:
  unsigned char code_;
};


int main() {

  std::vector<std::shared_ptr<FilterBase>> filters;
  filters.push_back(std::make_shared<ByCode>('A'));
  filters.push_back(std::make_shared<ByCode>('B'));

  std::shared_ptr<Token> p = std::make_shared<Token>('M', 20);
  std::vector<std::shared_ptr<Token>> tokens;
  tokens.push_back(p);
  filters[0]->operator ()(p);

  for (const std::shared_ptr<FilterBase> fi : filters) {
    tokens.erase(std::remove_if(tokens.begin(), tokens.end(), *fi), tokens.end());
  }
}

但不幸的是它没有编译,因为参数类型&#39; FilterBase&#39;是一个抽象类。嗯,我知道它是,我只是通过虚拟关键字使它工作...

1 个答案:

答案 0 :(得分:1)

替换:

tokens.erase(std::remove_if(tokens.begin(), tokens.end(), *fi), tokens.end());

使用:

tokens.erase(std::remove_if(tokens.begin(), tokens.end(), std::ref(*fi)), tokens.end());

remove_if使用其仿函数by-value,这会将*fi切成基类的实例,该实例具有纯virtual个对象。情况很糟糕。

std::ref有一个重载的operator(),如果MSVC没有搞砸了(例如,如果它调用运算符),它应该调用virtual operator() *fi错误的方式)。

如果失败,您可以编写自己的适配器:

template<typename T>
struct callable_by_ref {
  T* t;
  template<typename... Args>
  auto operator(Args&&...args) const ->
  decltype( std::declval<T&>()(std::declval<Args&&>()...) )
  {
    return (*t)(std::forward<Args>(args)...);
  }
};
template<typename T>
callable_by_ref< typename std::remove_reference<T>::type >
call_by_ref( T&& t ) {
  return {&t};
}

即使std::ref没有,也应解决您的问题。

tokens.erase(std::remove_if(tokens.begin(), tokens.end(), call_by_ref(*fi)), tokens.end());

我在做什么:

callable_by_ref基本上是一个快速完美的转发器,它上面有一个半功能的std::reference_wrapper实现。 call_by_ref为您创建此类对象的类型扣除。