包装谓词函子

发布于 2024-12-09 16:14:43 字数 1054 浏览 0 评论 0原文

我想知道有关谓词函子包装的约定和最佳实践。例如,给定一个像这样的类:

class Timer
{
public:
  Timer(const std::string& name, int interval);
  bool nameIs(const std::string& name) const;
private:
  std::string name_;
  int interval_;
};

(在一种情况下)在类 TimerVec: 中使用,

class TimerVec
{
public:
  typedef std::vector<Timer>::iterator iterator;``
  <... ctors, etc ...>
  iterator findByName(const std::string& name);
private:
  std::vector<Timer> timers_;
};

并且有一个像这样的谓词函子:

class TimerNameIs
{
public:
  TimerNameIs(const std::string& name) : name_(name) {}
  bool operator()(const Timer& t) { return t.nameIs(name_); }
private:
  const std::string& name_;
};

我可以想到很多地方可以放置函子代码,其中一些是:

  1. 在紧随 Timer 声明之后的头文件中
  2. 嵌套在 Timer 中(即,引用变为 Timer::TimerNameIs
  3. 嵌套在 TimerVec 中(当前是唯一用户)
  4. 在实现之前的匿名命名空间中TimerVec::findByName(又是唯一使用它的地方)

虽然其中任何一个都足够了,但我更喜欢#2,但这不是我见过的做法。是否有任何支持特定选项的具体原因?

I'm wondering about conventions and best practices regarding the packaging of predicate functors. For example, given a class like:

class Timer
{
public:
  Timer(const std::string& name, int interval);
  bool nameIs(const std::string& name) const;
private:
  std::string name_;
  int interval_;
};

that is (in one case) used in class TimerVec:

class TimerVec
{
public:
  typedef std::vector<Timer>::iterator iterator;``
  <... ctors, etc ...>
  iterator findByName(const std::string& name);
private:
  std::vector<Timer> timers_;
};

and has a predicate functor like:

class TimerNameIs
{
public:
  TimerNameIs(const std::string& name) : name_(name) {}
  bool operator()(const Timer& t) { return t.nameIs(name_); }
private:
  const std::string& name_;
};

I can think of a number of places to put the functor code, some being:

  1. In the header file immediately following the declaration of Timer
  2. Nested inside Timer (i.e. so the ref becomes Timer::TimerNameIs)
  3. Nested inside TimerVec (currently the only user)
  4. In an anonymous namespace ahead of the implementation for TimerVec::findByName (again the only place it's used)

While any of these would be adequate I'm rather drawn to #2, but it's not something I've ever seen done. Are there any concrete reasons favoring a particular option?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

烟若柳尘 2024-12-16 16:14:43

这有待商榷。我更喜欢创建一个嵌套类。这样,仅适用于特定类型对象的函子就在该对象内的命名空间范围内。

我通常还将谓词命名为 match_xxx,其中 xxx 是我要匹配的参数。

也就是说:

class Timer
{
  // ...
public:
  class match_name : public std::unary_function<Timer, bool>
  {
  public:
    match_name(const std::string& name) : name_(name) {}
    bool operator()(const Timer& t) { return t.nameIs(name_); }
  private:
    const std::string& name_;
  };
};

...这样使用:

std::find_if( v.begin(), v.end(), Timer::match_name("Flibbidy") );

我更喜欢这种方法,因为 6 个月后查看此代码时,Timer::match_name("Flibbidy") 的语义非常清晰。

我还小心地从 std::unary_function 派生我的函子(尽管我上面的派生可能会将参数颠倒)。

This is open to debate. I prefer to create a nested class. This way a functor that is intended only to work with a particular type of object is namespace-scoped within that object.

I also generally name the predicate match_xxx where xxx is the parameter I'm matching on.

To wit:

class Timer
{
  // ...
public:
  class match_name : public std::unary_function<Timer, bool>
  {
  public:
    match_name(const std::string& name) : name_(name) {}
    bool operator()(const Timer& t) { return t.nameIs(name_); }
  private:
    const std::string& name_;
  };
};

...which is utilized thusly:

std::find_if( v.begin(), v.end(), Timer::match_name("Flibbidy") );

I prefer this method because the semantics of Timer::match_name("Flibbidy") are exceedingly clear when looking at this code 6 months later.

I also am careful to derive my functor from std::unary_function (although my derivation above might have the parameters reversed).

哥,最终变帅啦 2024-12-16 16:14:43

就我个人而言,在它自己的头文件和 cpp 文件中。在 TimerNameIs 头文件中使用 #include "Timer.h"

#include "Timer.h"
#include <string>

class TimerNameIs
{
    public:
        TimerNameIs(const std::string& name) : name_(name) {}
        bool operator()(const Timer& t) { return t.nameIs(name_); }
    private:
        const std::string& name_;
};

这样做可以将 Timer 和 TimerNameIs 相互隔离。

Me, personally, in it's own header and cpp files. Using #include "Timer.h" in the TimerNameIsheader file:

#include "Timer.h"
#include <string>

class TimerNameIs
{
    public:
        TimerNameIs(const std::string& name) : name_(name) {}
        bool operator()(const Timer& t) { return t.nameIs(name_); }
    private:
        const std::string& name_;
};

Doing this, you isolate Timer and TimerNameIs from one to the other.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文