Assuming I had two classes, the first one for writing primitive types (bool
, int
, float
, etc.) and the second one extending the first to also write complex types:
struct Writer {
virtual void Write(int value) = 0;
};
struct ComplexWriter : public Writer {
template <typename TValue> void Write(const TValue &value) {
boost::any any(value);
Write(any);
}
//virtual void Write(int value) = 0; // see question below
virtual void Write(const boost::any &any) = 0;
};
The idea is that if someone calls myWriter.Write(someIntValue);
, the int overload will receive priority over the templated method.
Instead, my compiler (Visual C++ 11.0 RC) always picks the template method. The following code snippet, for example, will print Wrote any
to the console:
struct ComplexWriterImpl : public ComplexWriter {
virtual void Write(int value) { std::cout << "Wrote an int"; }
virtual void Write(const boost::any &any) { std::cout << "Wrote any"; }
};
void TestWriter(ComplexWriter &writer) {
int x = 0;
writer.Write(x);
}
int main() {
ComplexWriterImpl writer;
TestWriter(writer);
}
The behavior suddenly changes when I declare the Write(int)
method in the ComplexWriter
class as well (see commented out line in the first snippet). It then prints Wrote an int
to the console.
Is this how my compiler ought to behave? Does the C++ standard explicitly say that only overloads defined in the same class (and not a base class) shall be prioritized over a templated method?
Function overloading is used when multiple functions do similar operations; templates are used when multiple functions do identical operations. Templates provide an advantage when you want to perform the same action on types that can be different.
You may overload a function template either by a non-template function or by another function template. The function call f(1, 2) could match the argument types of both the template function and the non-template function.
A template function can be overloaded either by a non-template function or using an ordinary function template.
What is the difference between function overloading and templates? Both function overloading and templates are examples of polymorphism features of OOP. Function overloading is used when multiple functions do quite similar (not identical) operations, templates are used when multiple functions do identical operations.
The problem is that at the point you're calling writer.Write(x)
the compiler sees a ComplexWriter
not a ComplexWriterImpl
, so it is only aware of the functions defined in ComplexWriter
- the template function and the boost::any
function.
ComplexWriter
does not contain any virtual functions that accept an int
, so it has no way to call through to the int overload defined in ComplexWriterImpl
When you add in the virtual overload to the ComplexWriter
class, then the compiler becomes aware that there is an integer overload in the ComplexWriter
class and therefore calls through to it's implementation in ComplexWriterImpl
EDIT: Now that you've edited in the inheritance between ComplexWriter & Writer, I've got a more complete explanation for you:
When you create a subclass and define a function in it then all of the functions of that name in the base class will be hidden, regardless of their argument types.
You can get around this with the using keyword I believe:
struct ComplexWriter : public Writer {
template <typename TValue> void Write(const TValue &value) {
boost::any any(value);
Write(any);
}
using Writer::Write;
virtual void Write(const boost::any &any) = 0;
};
For more details see this FAQ entry: http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9
EDIT 2: Just to confirm that this does indeed solve your problem: http://ideone.com/LRb5a
When you access the object via the ComplexWriter
"interface", the compiler will try to resolve the function call to Write(int)
using the definitions in that class. If it does not able to do so, it will consider base classes.
In this case, you have two candidates: Write(any)
and the templated version. Since there is no explicit Write(int)
available at this point, it will have to choose between these two options. Write(any)
requires an implicit conversion, while the templated version does not, so the templated version is called (which in turn calls Write(any)
).
To make the Write(int)
from Writer
available, import the Writer::Write
functions:
class ComplexWriter : public Writer
{
using Writer::Write;
// rest is as before
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With