С++ функтор и шаблоны функций

рассмотрим этот простой и бессмысленный код.

#include <iostream>

struct A {
    template<int N>
    void test() {
        std::cout << N << std::endl;
    }
};

int main() {
    A a;
    a.test<1>();
}

Это очень простой пример шаблона функции. Что, если бы я захотел заменить A::test на перегруженный operator(), чтобы сделать его функтором?

#include <iostream>

struct A {
    template<int N>
    void operator()() {
        std::cout << N << std::endl;
    }
};

int main() {
    A a;
    a<1>(); // <-- error, how do I do this?
}

Конечно, если бы operator() принимал параметры, которые зависели от шаблона, компилятор мог бы вывести шаблон. Но я просто не могу понять правильный синтаксис для указания параметров шаблона с функтором без параметров.

Есть ли правильный способ сделать это?

Очевидно, этот код будет работать, поскольку он обходит синтаксис функтора:

a.operator()<1>();

но это как бы противоречит цели его функтора :-P.


person Evan Teran    schedule 02.06.2009    source источник
comment
+1: странный синтаксис для использования в запутывании кода. Следует упомянуть в thc.org/root/phun/unmaintain.html :-)   -  person Valentin Heinitz    schedule 15.09.2012


Ответы (5)


Я не знаю другого "прямого" способа, кроме:

 a.operator()<1>();

синтаксис. Если вы готовы изменить код, сработает перемещение параметра шаблона в класс или использование (boost|tr1)::bind для создания объекта (boost|tr1)::function.

person Todd Gardner    schedule 02.06.2009

Вы можете только позвонить

a.operator()<1>();

но это не будет использовать функтор. Функторам нужен нешаблонный оператор(), так как они должны вызываться как varname(), а это не будет работать с вашим кодом.

Чтобы сделать его настоящим функтором, измените свой код на класс шаблона (функторы — это классы):

#include <iostream>

template<int N>
struct A {
    void operator()() {
        std::cout << N << std::endl;
    }
};

int main() {
    A<1> a;
    a();
}
person lothar    schedule 02.06.2009

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

а.тест‹1>(); и a.operator()‹1>(); работают, потому что они служат шаблонными функциями.

Используйте boost::bind (проверьте библиотеки boost), чтобы исправить это.

struct A {
    void operator()(int n) {
        std::cout << n << std::endl;
    }
};

int main(int argc, char* argv[]) {
    A a;
    boost::function<void()> f = boost::bind<void>(a, 1);
    f(); // prints 1

    return 0;
}

И вам даже не придется возиться с шаблонами!

person Jeffrey Martinez    schedule 02.06.2009

Вы застряли. Вы рассматривали что-то вроде

struct A {
    template<int N>
    struct B
    {
        void operator()()
        { std::cout << N << std::endl; }
    };

    template<int N>
    B<N> functor() {return B<N>();}
};

int main()
{
    A a;
    a.functor<1>()();
}
person rlbond    schedule 02.06.2009

Нет, нет никакого способа обойти это. Как вы сказали, вы должны либо явно вызвать оператор (что противоречит цели), либо аргументы шаблона должны быть в состоянии быть выведены компилятором.

person jalf    schedule 02.06.2009