Что такое функторы C ++ и их использование?

Вот как вы можете это сделать, используя циклы.

public static int[][] makeCopy(int[][] array){
    b=new int[array.length][];

    for(int row=0; row<array.length; ++row){
        b[row]=new int[array[row].length];
        for(int col=0; col<b[row].length; ++col){
            b[row][col]=array[row][col];
        }
    }
    return b;
}
804
задан Ciro Santilli 新疆改造中心996ICU六四事件 29 June 2018 в 10:41
поделиться

5 ответов

Функтор является в значительной степени просто классом, который определяет оператор (). Это позволяет Вам создать объекты, которые похожи" на функцию:

// this is a functor
struct add_x {
  add_x(int x) : x(x) {}
  int operator()(int y) const { return x + y; }

private:
  int x;
};

// Now you can use it like this:
add_x add42(42); // create an instance of the functor class
int i = add42(8); // and "call" it
assert(i == 50); // and it added 42 to its argument

std::vector<int> in; // assume this contains a bunch of values)
std::vector<int> out(in.size());
// Pass a functor to std::transform, which calls the functor on every element 
// in the input sequence, and stores the result to the output sequence
std::transform(in.begin(), in.end(), out.begin(), add_x(1)); 
assert(out[i] == in[i] + 1); // for all i

существует несколько хороших вещей о функторах. Каждый - это в отличие от регулярных функций, они могут содержать состояние. Вышеупомянутый пример создает функцию, которая добавляет 42 к тому, что Вы даете ему. Но то значение 42 не является hardcoded, оно было определено как аргумент конструктора, когда мы создали наш экземпляр функтора. Я мог создать другой сумматор, который добавил 27, только путем вызова конструктора с различным значением. Это делает их приятно настраиваемыми.

, Поскольку последние строки показывают, Вы часто передаете функторы как аргументы другим функциям, таким как станд.:: преобразуйте или другие стандартные алгоритмы библиотеки. Вы могли сделать то же с указателем регулярной функции кроме, как я сказал выше, функторы могут быть "настроены", потому что они содержат состояние, делая их более гибкими (Если бы я хотел использовать указатель функции, я должен был бы записать функцию, которая добавила точно 1 к ее аргументу. Функтор является общим, и добавляет, что Вы инициализировали его с), и они также потенциально более эффективны. В вышеупомянутом примере компилятор знает точно, какая функция std::transform должна вызвать. Это должно звонить add_x::operator(). Это означает, что может встроить тот вызов функции. И это делает его столь же эффективным, как будто я вручную вызвал функцию на каждом значении вектора.

, Если я передал указатель функции вместо этого, компилятор не мог бы сразу видеть, на какую функцию он указывает на, поэтому если он не выполняет некоторую довольно сложную глобальную оптимизацию, он должен был бы разыменовать указатель во времени выполнения, и затем выполнить вызов.

969
ответ дан T.C. 29 June 2018 в 10:41
поделиться

Как другие упомянули, функтор является объектом, который действует как функция, т.е. он перегружает оператор вызова функции.

Функторы являются наиболее часто используемыми в алгоритмах STL. Они полезны, потому что они могут содержать состояние прежде и между вызовами функции, как закрытие на функциональных языках. Например, Вы могли определить MultiplyBy функтор, который умножает его аргумент на указанную сумму:

class MultiplyBy {
private:
    int factor;

public:
    MultiplyBy(int x) : factor(x) {
    }

    int operator () (int other) const {
        return factor * other;
    }
};

Тогда Вы могли передать MultiplyBy объект к алгоритму как станд.:: преобразуйте:

int array[5] = {1, 2, 3, 4, 5};
std::transform(array, array + 5, array, MultiplyBy(3));
// Now, array is {3, 6, 9, 12, 15}

Другое преимущество функтора по указателю на функцию состоит в том, что вызов может быть встроен в большем количестве случаев. При передаче указателя функции transform если , что вызов был встроен и компилятор не знает, что Вы всегда передаете ту же функцию ему, это не может встроить вызов через указатель.

37
ответ дан Lightness Races in Orbit 29 June 2018 в 10:41
поделиться

Функтор является объектом, который действует как функция. В основном, класс, который определяет operator().

class MyFunctor
{
   public:
     int operator()(int x) { return x * 2;}
}

MyFunctor doubler;
int x = doubler(5);

реальное преимущество состоит в том, что функтор может содержать состояние.

class Matcher
{
   int target;
   public:
     Matcher(int m) : target(m) {}
     bool operator()(int x) { return x == target;}
}

Matcher Is5(5);

if (Is5(n))    // same as if (n == 5)
{ ....}
90
ответ дан Ziezi 29 June 2018 в 10:41
поделиться

Мало дополнения. Можно использовать boost::function , для создания функторов из функций и методов, как это:

class Foo
{
public:
    void operator () (int i) { printf("Foo %d", i); }
};
void Bar(int i) { printf("Bar %d", i); }
Foo foo;
boost::function<void (int)> f(foo);//wrap functor
f(1);//prints "Foo 1"
boost::function<void (int)> b(&Bar);//wrap normal function
b(1);//prints "Bar 1"

и можно использовать повышение:: свяжите для добавления состояния к этому функтору

boost::function<void ()> f1 = boost::bind(foo, 2);
f1();//no more argument, function argument stored in f1
//and this print "Foo 2" (:
//and normal function
boost::function<void ()> b1 = boost::bind(&Bar, 2);
b1();// print "Bar 2"

и самый полезный с повышением:: свяжите и повысьте:: функция можно создать функтор из метода класса, на самом деле это - делегат:

class SomeClass
{
    std::string state_;
public:
    SomeClass(const char* s) : state_(s) {}

    void method( std::string param )
    {
        std::cout << state_ << param << std::endl;
    }
};
SomeClass *inst = new SomeClass("Hi, i am ");
boost::function< void (std::string) > callback;
callback = boost::bind(&SomeClass::method, inst, _1);//create delegate
//_1 is a placeholder it holds plase for parameter
callback("useless");//prints "Hi, i am useless"

можно создать список или вектор функторов

std::list< boost::function<void (EventArg e)> > events;
//add some events
....
//call them
std::for_each(
        events.begin(), events.end(), 
        boost::bind( boost::apply<void>(), _1, e));

существует одна проблема со всем этим материалом, ошибка компилятора обменивается сообщениями, не человекочитаемо:)

117
ответ дан Ziezi 29 June 2018 в 10:41
поделиться

Имя «функтор» традиционно использовалось в теории категорий задолго до того, как на сцене появился C ++. Это не имеет ничего общего с концепцией функтора в C ++. Это' Лучше использовать имя объект функции вместо того, что мы называем «функтором» в C ++. Так другие языки программирования вызывают аналогичные конструкции.

Используется вместо простой функции:

Особенности:

  • Функциональный объект может иметь состояние
  • Функциональный объект вписывается в ООП (он ведет себя как любой другой объект).

Минусы:

  • Повышает сложность программы.

Используется вместо указателя функции:

Особенности:

  • Функциональный объект часто может быть встроен

Минусы:

  • Функциональный объект не может быть заменяется другим типом функционального объекта во время выполнения (по крайней мере, если он не расширяет какой-либо базовый класс, что, следовательно, дает некоторые накладные расходы)

Используется вместо виртуальной функции:

Характеристики:

  • Функциональный объект (не виртуальный) не ' t требует диспетчеризации vtable и runtime, таким образом, он более эффективен в большинстве случаев.

Минусы:

  • Функциональный объект не может быть заменен другим типом функционального объекта во время выполнения (по крайней мере, если он не расширяет некоторый базовый класс, что, следовательно, вызывает некоторые накладные расходы)
49
ответ дан 22 November 2019 в 21:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: