35

In C++, can you have a templated operator on a class? Like so:

class MyClass {
public:
    template<class T>
    T operator()() { /* return some T */ };
}

This actually seems to compile just fine, but the confusion comes in how one would use it:

MyClass c;
int i = c<int>(); // This doesn't work
int i = (int)c(); // Neither does this*

The fact that it compiles at all suggests to me that it's doable, I'm just at a loss for how to use it! Any suggestions, or is this method of use a non-starter?

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Toji
  • 33,927
  • 22
  • 105
  • 115

3 Answers3

50

You need to specify T.

int i = c.operator()<int>();

Unfortunately, you can't use the function call syntax directly in this case.

Edit: Oh, and you're missing public: at the beginning of the class definition.

avakar
  • 32,009
  • 9
  • 68
  • 103
  • 1
    Nice. Kudos on the quick and accurate answer! Unfortunately that's probably to verbose for my uses (since my code is intended to be called by others I want to avoid confusion) so I'll just have to find another route. Thanks again! – Toji Jul 12 '09 at 18:58
  • 5
    Yes, you're probably better off defining a `get` method instead of `operator()`. Then you could write `c.get()`. – avakar Jul 12 '09 at 19:01
  • Actually, there is an idiom flying around that's used by many: free get function (tuples use `get(some_tuple)`, boost.variant uses `get(some_variant)`). So yours would look like `get(c)`, with `get` being defined in `MyClass`'es namespace). – Johannes Schaub - litb Jul 12 '09 at 20:07
  • In this case I needed both a call that returned a value and one that didn't. I implemented *Evaluate()* for the returning version, and *Execute()* for the non-returning, and then allowed the user to call the () operator as an alternative to Evaluate. (The names make sense in context, since they are executing functions defined in a script.) So essentially, yes, I implemented a get function :) Thanks for all the suggestions! – Toji Jul 13 '09 at 19:40
21

You're basically right. It is legal to define templated operators, but they can't be called directly with explicit template arguments.

If you have this operator:

template <typename T>
T operator()();

as in your example, it can only be called like this:

int i = c.operator()<int>();

Of course, if the template argument could be deduced from the arguments, you could still call it the normal way:

template <typename T>
T operator()(T value);

c(42); // would call operator()<int>

An alternative could be to make the argument a reference, and store the output there, instead of returning it:

template <typename T>
void operator()(T& value);

So instead of this:

int r = c.operator()<int>();

you could do

int r;
c(r);

Or perhaps you should just define a simple get<T>() function instead of using the operator.

jalf
  • 243,077
  • 51
  • 345
  • 550
4

Aren't you thinking of

class Foo {
    public:
    template<typename T>
    operator T() const { return T(42); }
};

Foo foo;

int i = (int) foo; // less evil: static_cast<int>(foo);

live example. This proves you do not need to specify the template argument, despite the claim in the accepted answer.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • Works in this case, but I was thinking of `c++`. I mean this shouldn't work, and I am kinda abusing notation there... – Post Self Apr 15 '17 at 18:48
  • @kim366: Since that has no meaning, it's rather pointless to think about it. It shouldn't work, and it doesn't work. – MSalters Apr 15 '17 at 19:08