我可以使用私有嵌套结构体编写函数对象(functor)吗?

5

考虑以下类:

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;
    }
};
6个回答

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;
}

2
我会这样做。
标题:
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,我忘记了可以将functor定义为嵌套结构体。我也为你修正了一个错别字(复制-粘贴-哦?)。 - Michael Kristofik
@Kristo: 复制粘贴?当然可以! ;) - Johann Gerell

1
你可以将函数对象设为 C 的友元。

1

+1,所有我建议使用multi_index但从未得到点赞的时候;) - pmr

0

如果您不需要在头文件中使用结构体,您也可以在实现文件中使用未命名的命名空间,使定义和声明局部于编译单元(使用C语言风格的替代方案是static)。

这样可以让您拥有一个更干净的头文件,而不会被实现细节所遮盖。


我认为Foo仍然需要在头文件中声明,因为fooList依赖于它。 - Michael Kristofik
@Kristo:当然可以,但问题是关于函数对象而不是结构体本身。真正的问题是,结构体Foo是否只是实现细节,还是应该在类外提供它。 - pmr

0

我可以使用Pimpl惯用语C的私有部分隐藏在另一个类中。由于CImpl中的所有内容都可以安全地公开,因此我应该能够在那里随心所欲地处理Foo


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接