开发者

Can I write functors using a private nested struct?

开发者 https://www.devze.com 2022-12-23 14:27 出处:网络
Given this class: class C { private: struct Foo { int key1, key2, value; }; std::vector<Foo> fooList; };

Given this class:

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

The idea here is that fooList can be indexed by either key1 or key2 of the Foo struct. I'm trying to write functors to pass to std::find_if so I can look up items in fooList by each key. But I can't get them to compile because Foo is private within the class (it's not part of C's interface). Is there a way to do this without exposing Foo to the rest of the world?

Here's开发者_高级运维 an example of code that won't compile because Foo is private within my class:

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


I'd do something like this.

Header:

class C
{
private:
    struct Foo
    {
        int index;
        Bar bar;
    };

    // Predicates used to find Notification instances.
    struct EqualIndex;
    struct EqualBar;

    std::vector<Foo> fooList;
};

Source:

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

Usage:

// 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.
}

Sort of...


Yes. Make the functor another member of C and encapsulate std::find_if behind a method of C.

Following is an example:

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


You could make the functor a friend of C.


The syntax is pretty baroque, but I could turn fooList into a boost::multi_index_container indexed on key1 and key2.


If you don't need your struct inside your header you could also use unnamed namespaces in your implementation file to make the definitions and declarations local to the compilation unit (with static being the C-like alternative static).

This leaves you with a cleaner header that isn't obscured by implementation details.


I could use the Pimpl Idiom to hide the private section of C inside another class. Since everything in CImpl can safely be public, I should be able to do whatever I want with Foo there.

0

精彩评论

暂无评论...
验证码 换一张
取 消