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,
Can I actually do what I’m trying to do with some other syntax?
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.
No, you’ll need to do something like your second example above; passing the template-typed variable as a parameter, because…
…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++.
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. . .
(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 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.