【问题标题】:Can I write functors using a private nested struct?我可以使用私有嵌套结构编写仿函数吗?
【发布时间】:2010-03-22 15:29:04
【问题描述】:

鉴于这个类:

class C
{
    private:
        struct Foo
        {
            int key1, key2, value;
        };
        std::vector<Foo> fooList;
};

这里的想法是fooList 可以被Foo 结构的key1key2 索引。我正在尝试编写函子以传递给std::find_if,以便我可以通过每个键查找fooList 中的项目。但我无法让它们编译,因为Foo 在类中是私有的(它不是 C 接口的一部分)。 有没有办法在不将Foo 暴露给世界其他地方的情况下做到这一点?

这是一个无法编译的代码示例,因为 Foo 在我的班级中是私有的:

struct MatchKey1 : public std::unary_function<Foo, bool>
{
    int key;
    MatchKey1(int k) : key(k) {}
    bool operator()(const Foo& elem) const
    {
        return key == elem.key1;
    }
};

【问题讨论】:

    标签: c++ nested private functor


    【解决方案1】:

    我会做这样的事情。

    标题:

    class C
    {
    private:
        struct Foo
        {
            int index;
            Bar bar;
        };
    
        // Predicates used to find Notification instances.
        struct EqualIndex;
        struct EqualBar;
    
        std::vector<Foo> fooList;
    };
    

    来源:

    // Predicate for finding a Foo instance by index.
    struct C::EqualIndex : std::unary_function<C::Foo, bool>
    {
        EqualIndex(int index) : index(index) { }
        bool operator()(const C::Foo& foo) const { return foo.index == index; }
        const int index;
    };
    
    // Predicate for finding a Foo instance by Bar.
    struct C::EqualBar : std::unary_function<C::Foo, bool>
    {
        EqualBar(const Bar& bar) : bar(bar) { }
        bool operator()(const C::Foo& foo) const { return foo.bar == bar; }
        const Bar& bar;
    };
    

    用法:

    // Find the element containing the Bar instance someBar.
    std::vector<Foo>::iterator it = std::find_if(fooList.begin(),
                                                 fooList.end(),
                                                 EqualBar(someBar));
    
    if (it != fooList.end())
    {
        // Found it.
    }
    

    有点……

    【讨论】:

    • +1,我忘了简单地将仿函数声明为嵌套结构。我也为你修正了一个错字(复制粘贴?)。
    • @Kristo:复制粘贴?你打赌! ;)
    【解决方案2】:

    是的。使函子成为C 的另一个成员,并将std::find_if 封装在C 的方法后面。

    以下是一个例子:

    #include "stdafx.h"
    #include <vector>
    #include <cassert>
    #include <algorithm>
    #include <iostream>
    
    class C
    {
        private:
            struct Foo
            {
                int key1, key2, value;
            };
    
            std::vector<Foo> fooList;
    
        struct Finder
        {
        private:
          int key1, key2;
    
        public:
          Finder(int k1, int k2)
          {
            key1 = k1;
            key2 = k2;
          }
    
          bool operator ()(Foo const& foo) const
          {
            return foo.key1 == key1 || foo.key2 == key2;
          }
        };
    
    public:
      C()
      {
        Foo foo1, foo2;
        foo1.key1 = 5;
        foo1.key2 = 6;
        foo1.value = 1;
        foo2.key1 = 7;
        foo2.key2 = 8;
        foo2.value = 10;
    
        fooList.insert(fooList.begin(), foo1);
        fooList.insert(fooList.begin(), foo2);
      }
    
      int Find(int key1, int key2)
      {
        return std::find_if(fooList.begin(), fooList.end(), Finder(key1, key2))->value;
      }
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
      C c;
    
      std::cout << c.Find(5, 3) << std::endl;
      std::cout << c.Find(3, 6) << std::endl;
      std::cout << c.Find(7, 3) << std::endl;
      std::cout << c.Find(3, 8) << std::endl;
    
      return 0;
    }
    

    【讨论】:

      【解决方案3】:

      你可以让函子成为C的朋友。

      【讨论】:

        【解决方案4】:

        语法很巴洛克,但我可以将fooList 转换为boost::multi_index_container 索引在key1key2 上。

        【讨论】:

        • +1,一直以来我都建议使用 multi_index,但从未获得过投票;)
        【解决方案5】:

        如果你不需要你的头文件中的结构,你也可以在你的实现文件中使用未命名的命名空间来使编译单元的定义和声明成为本地的(静态是类 C 的替代品static)。

        这为您提供了一个更清晰的标题,不会被实现细节所掩盖。

        【讨论】:

        • 我觉得Foo还是需要在头部声明,因为fooList依赖它。
        • @Kristo:当然,但问题是关于函子而不是结构本身。真正的问题是 struct Foo 是否真的只是一个实现细节,或者它是否应该在你的类之外提供。
        【解决方案6】:

        我可以使用Pimpl IdiomC 的私有部分隐藏在另一个类中。因为CImpl 中的所有内容都可以安全地公开,所以我应该可以在那里使用Foo 做任何我想做的事情。

        【讨论】:

          猜你喜欢
          • 2014-06-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-07-07
          • 2014-06-30
          • 2014-05-31
          相关资源
          最近更新 更多