views:

1329

answers:

5

consider this simple and pointless code.

#include <iostream>

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

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

It is a very simple example of a function template. What if however, I wanted to replace A::test with an overloaded operator() to make it a functor?

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

Certainly if the operator() took parameters which were dependent on the template, the compiler could possibly deduce the template. But I just can't figure out the proper syntax to specify template parameters with a parameterless functor.

Is there a proper way to do this?

Obviously, this code would work since it bypasses the functor syntax:

a.operator()<1>();

but that kinda defeats the purpose of it being a functor :-P.

+3  A: 

There's not another "direct" way I know other than the:

 a.operator()<1>();

syntax. If you're open to changing the code, moving the template parameter to the class would work, or using a (boost|tr1)::bind to make a (boost|tr1)::function object.

Todd Gardner
+11  A: 

You can only call

a.operator()<1>();

but that would not be using a functor. Functors need a non template operator(), as they must be able to be called as varname() and that won't work with your code.

To make it a real functor change your code a template class (functors are classes):

#include <iostream>

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

int main() {
    A<1> a;
    a();
}
lothar
+1  A: 

You are trying to pass a template parameter to an instance of an object, which as far as I know is not allowed. You can only pass templates parameters to template functions or template objects.

a.test<1>(); and a.operator()<1>(); work because they are serving as template functions.

Use boost::bind (check out boost libraries) to fix it though.

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

And you don't even have to mess with templates!

Jeffrey Martinez
A: 

Nope, there's no way around it. Like you said, you have to either call the operator explicitly (which defeats the purpose), or the template arguments must be able to be deduced by the compiler.

jalf
A: 

You're stuck. Have you considered something like

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>()();
}
rlbond