Reputation: 59496
In my C++/CLI code, I have about 20 different classes. I have overloaded a print
function 20 times to handle an instance of each class. Now I need to additionally support arrays of objects of each of those 20 classes and hate to have to write another 20 overloads which are mostly verbatim copies of each other. As an example, see below:
void print(int i){
Console::WriteLine("Integer: {0}", i);
}
void print(String ^s){
Console::WriteLine(L"Hello " + s);
}
generic <typename T>
void print(array<T> ^ts){
for(int i = 0, n = ts->Length; i < n; ++i)
print(ts[i]);
}
int main(array<System::String ^> ^args)
{
array<String^> ^s = gcnew array<String^>{ L"apple", L"ball", L"car" };
print(s);
Console::WriteLine(L"Hello World");
return 0;
}
But the above results in the following error:
error C2665: 'print' : none of the 2 overloads could convert all the argument types
Why doesn't this compile? What is the alternative for what I am trying to do?
Upvotes: 1
Views: 876
Reputation: 20812
The reason it can't be compiled is that there is no print<T>
function. The only print
functions are for int
and String
.
A C++ template will work:
template <class T>
void print(array<T> ^ts){
for(int i = 0, n = ts->Length; i < n; ++i)
print(ts[i]);
}
Upvotes: 2
Reputation: 27874
The reason it doesn't compile is that generic methods, unlike template methods, exist for all types possible. Template methods are created just when they are called. Since you're only calling print
with a string array, a template method definition would compile a version that explicitly takes a string array, and nothing else. It would be implemented to call the print(String^)
method, and there'd be no errors.
Since it's generic, there's only one compiled version of the method. If you pass a T
to another method, there has to be an overload of that method that can take any parameter, even ones you're not using in your program. For this method, if you're going to pass a T
to a method, it has to take a parameter of type Object^
.
To make this work, I'd implement print
so that it takes an Object, and use reflection to find the class name to print.
void print(Object^ o)
{
Console::WriteLine("{0}: {1}", o->GetType()->Name, o);
}
generic <typename T>
void print(array<T> ^ts){
for(int i = 0, n = ts->Length; i < n; ++i)
print(ts[i]);
}
If you want to provide specific versions for specific types, implement some additional logic in the print method:
void print(Object^ o){
if(o->GetType() == String::typeid)
Console::WriteLine("Hello {0}", o);
else
Console::WriteLine("{0}: {1}", o->GetType()->Name, o);
}
generic <typename T>
void print(array<T> ^ts){
for(int i = 0, n = ts->Length; i < n; ++i)
print(ts[i]);
}
Upvotes: 1