Приближение алгоритмов STL, лямбда, локальных классов и других подходов

Одной из вещей, которая кажется необходимой при использовании STL, является способ задания локальных функций. Многие из функций, которые я обычно предоставляю, не могут быть созданы с использованием инструментов создания объектов функции STL (например, bind), мне нужно вручную перевернуть мой объект функции.

Поскольку стандарт С++ запрещает использование локальных типов в качестве аргументов в экземплярах шаблонов, лучшим из которых я смог воспользоваться, было создание небольшой библиотеки (просто показ соответствующих частей)

// library header
class MyFunctionBase<R,T>  
{  
 public:  
   virtual ~MyFunctionBase();  
   virtual R operator()(const T &) const=0;  
};    


class  MyFunction<R,T> 
{   
    MyFunctionBase<R,T> *b; 
 public: 
    ~MyFunction()
    {
       delete b;
    }
    virtual R operator()(const T &) const
    {
        return (*b)(T);
    } 
};


// source file
....

    class func: public MyFunctionBase  ...
    std::stl_alg(....    MyFunction(new funct));

Это всегда казалось мне необоснованным. Я думаю, что люди в комитете ИСО тоже так считают и добавили лямбду на С++.

Тем временем, как компиляторы решали эту проблему? (Особенно компиляторы Windows.)

Коррекция, которая может немного уточнить. Changelog: 2 ноября заменить для уточнения Поскольку стандарт С++ запрещает локальные классы как объекты функций

Ответ 1

Boost.Bind, Boost.Function и Boost.Lambda - ваши друзья.

Ответ 2

Стандартный способ - это "функтор" - в основном, struct, который снабжает operator()

Например:

struct MyMinFunctor {
  bool operator()(const int& a, const int& b) { return a > b; }
};

vector<int> v;
sort(v.begin(), v.end(), MyMinFunctor());

Поскольку это struct/class, вы можете подклассифицировать любую из таких вещей, как "binary_operator", а также поддерживать состояние для более продвинутых функторов.

Ответ 3

С С++ 0x вы можете использовать лямбда (как вы упомянули):

for_each(container.begin(), container.end(),
  [](auto item) {
    // do something with item
  }
  );

Это уже доступно в MS Visual С++ 2010 (в настоящее время в Community Tech Preview) и GCC 4.3.x(с флагом -std = С++ 0x). Однако без лямбда вам просто нужно указать тип, который:

  • По умолчанию конструктивен
  • Является ли копирование конструктивным
  • Определяет перегрузку оператора функции

Существуют некоторые алгоритмы, которые требуют двоичных функциональных объектов, в то время как есть некоторые, которые требуют унарных объектов функции. Обратитесь к документации вашего поставщика STL, чтобы узнать, какие именно алгоритмы требуют двоичных функциональных объектов, а какие - унарные объекты функции.

Одна вещь, которую вы также можете изучить, - это новые реализации bind и function в TR1 (на основе Boost.Bind и Boost.Function).