【问题标题】:Use operator! to negate an overloaded boolean predicate使用运算符!否定一个重载的布尔谓词
【发布时间】:2013-10-27 12:53:00
【问题描述】:

上下文:仅限 C++03 + 授权使用 boost

我想提出与中相同的问题

How to negate a predicate function using operator ! in C++?

...但带有一个重载的布尔谓词,即:

struct MyPredicate
{
    bool operator()(T1) const;
    bool operator()(T2) const;
};

显然,MyPredicate 不能从 std::unary_function 派生,因为不可能定义单个 argument_type

目的是使用MyPredicate 作为range adaptors 的参数,语法如下:

using boost::for_each;
using boost::adaptors::filtered;

list<T1> list1;
list<T2> list2;

for_each(list1 | filtered(!MyPredicate()), doThis);
for_each(list2 | filtered(!MyPredicate()), doThat);

当然,任何涉及明确消歧的解决方案在这里都不感兴趣。

提前谢谢你。

[接受的解决方案]

我正在使用 Angew 解决方案的略微修改版本:

template <class Predicate>
struct Not
{
  Predicate pred;

  Not(Predicate pred) : pred(pred) {}

  template <class tArg>
  bool operator() (const tArg &arg) const
  { return !pred(arg); }
};

template <class Pred>
inline Not<Pred> operator! (const Pred &pred)
{
  return Not<Pred>(pred);
}

template <class Pred>
Pred operator! (const Not<Pred> &pred)
{
  return pred.pred;
}

注意运算符 && 和 ||同样可以从这个技巧中受益。

【问题讨论】:

  • 可以使用多重继承吗? struct MyPredicate : unary_function&lt;T1, bool&gt;, unary_function&lt;T2, bool&gt;
  • 我没有尝试,但鉴于 unary_function 派生将定义 argument_type,我没有理由认为这不会导致定义冲突。

标签: c++ boost functional-programming


【解决方案1】:

你其实可以从std::unary_function派生:

template<typename T>
struct MyPredicate : std::unary_function<T, bool>
{
    bool operator()(T) const;
};

【讨论】:

  • 除非我弄错了,否则这需要明确的消歧 (filtered(!MyPredicate&lt;T1&gt;())),对吧?
  • @Koral:没错。我错过了想要避免它的问题底部的声明......
【解决方案2】:

你可以这样做:

struct MyPredicate
{
  bool positive;
  MyPredicate() : positive(true) {}

  bool operator() (T1) const {
    return original_return_value == positive;
  }
  bool operator() (T2) const {
    return original_return_value == positive;
  }
};

inline MyPredicate operator! (MyPredicate p) {
  p.positive = !p.positive;
  return p;
}

为了解决您忘记使用positive 的问题,您可以尝试使用包装类的替代方法。

template <class Predicate>
struct NegatablePredicate
{
  Predicate pred;
  bool positive;

  NegatablePredicate(Predicate pred, bool positive) : pred(pred), positive(positive) {}

  template <class tArg>
  bool operator() (const tArg &arg) const
  { return pred(arg) == positive; }
};

template <class Pred>
inline NegatablePredicate<Pred> operator! (const Pred &pred)
{
  return NegatablePredicate<Pred>(pred, false);
}

您还可以添加重载以进行优化:

template <class Pred>
inline NegatablePredicate<Pred> operator! (const NegatablePredicate<Pred> &pred)
{
  return NegatablePredicate<Pred>(pred.pred, !pred.positive);
}

要解决模板operator! 的广泛范围可能存在的问题,您可以使用boost::enable_if 魔术。

【讨论】:

  • 这应该可行,但我不满意,因为它不是万无一失的:必须考虑与positive 进行比较,否则operator! 将无法按预期工作,这不可能在编译时检测到。
  • 旁注:为避免为每个谓词定义operator!,可以将布尔值封装到基类BooleanPredicate 中,在该基类上可以一劳永逸地定义operator!
  • @koral 我添加了一个应该是万无一失的替代方案。
  • 这行得通,谢谢。我仍然觉得我们正在重新实现 boost::lambdaboost::phoenix 中已经完成的工作,尽管我不知道如何使用这些库来获得相同的结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-23
  • 1970-01-01
  • 1970-01-01
  • 2014-01-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多