C++ question (templates)

Now, I know you can’t overload an operator by return type, but can you do this. . .

Let’s say I have a class designed as such. . .


template <class T>
Trunk
{
   member<T> m;
};

Now, I want to write a function like this. . .


template <class T>
Trunk<T> f()
{
   //something.
   Trunk<T> t;
   //something
   return t;
}

And then in the code, I do something like this. . .



int main()
{
   Trunk<double> d; 
   d = f();
}

or


int main()
{
   Trunk<long> l; 
   l = f();
}

BZZZZT!

I can get the function to compile fine, but it doesn’t like the call. Naturally, I can work around it with something like



template <class T>
void f(Trunk<T>& t)
{	
   //do something
}

Then doing this is fine. . .



Trunk<double> d;
f(d);

I can kind of feel why what I’m doing is wrong even though it looks somewhat logical. I think I’m asking the compiler to know what KIND of thing Trunk is going to be at runtime, or soemthing. So,

  1. Can I actually do what I’m trying to do with some other syntax?

  2. For my own edification, what’s the actual issue here?

It seems to me that the issue is the same one you named at the beginning: You’re trying to do ambiguity resolution (here, to create a particular instance of a templated function) based on the return type of the function. This is not permitted in C++; I assume this is because doing so would require the parser to look both inward and outward to try to resolve ambiguities, in contrast to the current method where ambiguities are always resolved from the inside out.

But why don’t you want to do something like


template <class T>
Trunk
{
   member<T> m;

public:
   void f() { /* do something to *this; */ }
};

int main() {
  Trunk<double> d;
  d.f();
}

–that is, since you want a templated function associated with the templated class, just make the function a method of the templated class.

If you really wanted you could make f an overloaded unary operator (e.g., ! ~ + - ++ – *) to avoid the function-call syntax:



  void operator~() { /* do something to *this */ }

  // ...

  ~d;


I don’t actually have access to the templated class (in this case, Trunk).

I mean, I have the source code and all, but it’s third party. I’m adding functions that operate on the classes, but i"m not actually adding anything to the classes.

  1. No, you’ll need to do something like your second example above; passing the template-typed variable as a parameter, because…

  2. …overloading (of functions as well as operators) only allows resolution on the parameters, not the return type. Template functions are by definition overloads, even if there’s only one of them.

See the C++ Standard, section 13, for details if you want it. The justification for this isn’t given explicitly, but I suspect that it’s for when you cast a function result:

int x = (int)function_with_overloads();

…how would you know which one to call?

Incidentally, there’s an increasing movement to use “typename” rather than “class” for template specifications, since class is overloaded to mean something else. The two are interchangeable, so:

template <class T> foobar(T& barfoo);

and

template <typename T> foobar(T& barfoo);

are the same declaration, except the second one’s more explicit, always a plus in C++.

… How about deriving from the third-party classes?


template<class T> class Trunk {
  // ...
};

template<class T> class MyTrunk : public Trunk<T> {
public:
  void operator~( ) { /* ... */ }
};

Can you call your template function like this:



int main()
{
   Trunk<double> d; 
   d = f<double>();
}

?

Thanks.

TimeWinder, your (2) is pretty much what I thought. (I used to live in Corvallis, btw)

Ompha, I could try that but at that point, its getting more convoluted than my original work-around.

SomeGuy, that was actually something I tried, but no dice.

Really? I find Ompha’s solution of deriving from the base to be a lot clearer to follow than your workaround. Of course, that’s just MHO, no offense. :slight_smile:

For completeness, this also works. . .

Actual function I desire that doesn’t work:


template <class T>
Trunk<T> f(long l)
{
   Trunk<T> t;
   //something
   return t;
}

function that works:


template <class T>
Trunk<T> f(Trunk<T>& dummy, long l)
{
   Trunk<T> t;
   //something that does NOTHING to dummy
   return t;
}

Which might look overloaded by return type (and a similar function was actually the original source of my confusion) but is really just plain-old vanilla overloaded by parameter type.

And, as we desire, the compiler pukes if I try to do something like this. . .



int main() 
{
Trunk<long> t;
Trunk<double> t2;

t2 = f(t, 3);
}

Makes sense to me, now.

I’m confused then. What complaint does your compiler issue when you do that?

I’m sorry. That did work.

I might have forgot to save the header file.

(I’m building a library in one project, and then adding that library to another bit of code that I’m using to test the library. Problem is, in Borland, it will do the library build using your alterations without resaving the altered header file. You need to save that explicitly.)

I think that’s the right way to go then (the way you’re “supposed” to do it).

You have a paragraph of comments around that one, right?

I wouldn’t actually do that in code I expected anyone else from now to eternity to see.

I talked to a guy today with some experience with this. He also said that calling



f<T>(); 

is the way to go.

I just was a little blinded because I was stripping down an original function that was defined with the return type in the parameter list and I got problems when I wanted to take it out.

I envisioned code like



Trunk<double> dT = f(5);
Trunk<int> iT = f(5);


which I think we’d all be fine with if it stopped there. But the real ambiguity problems arise when you have



g(Trunk<int>) { /* do something */ }
g(Trunk<double>) {/* do something */}


And someone just goes and calls


g(f(5));

Which is just the basic argument against overloading by return type. I just blew right past it though.