I wrote a sample application to point out what I am trying to do. I have a template that I want to behave differently for a single data type and I would like to hide that from the calling program. In the code below, the intention is that if the data type is UnicodeString, I want it to use my override function; otherwise, I want it to use the template. It would also work to just modify the template and get rid of my override function, if that is possible.
If TRY_TO_OVERRIDE_TEMPLATE is defined, it looks like the compiler gives up because it can't decide which template to use.
If DO_NOT_EXPLICITLY_REFERENCE_TEMPLATE is defined, it causes a compile time error.
If neither of the defines are defined, it does a string concatenation, rather than converting each string to integer and adding the numerical values together.
I am using the current edition of C++ Builder, by the way.
//#define TRY_TO_OVERRIDE_TEMPLATE // results in "Unresolved external 'System::UnicodeString __fastcall MyMath::MyAddSystem::UnicodeString(System::UnicodeString, System::UnicodeString)' referenced from ...\UNIT1.OBJ" //#define DO_NOT_EXPLICITLY_REFERENCE_TEMPLATEclass MyMath {
public:
MyMath() {};
#ifdef TRY_TO_OVERRIDE_TEMPLATE
template <typename T> UnicodeString __fastcall MyAdd(UnicodeString a, UnicodeString b);
#else
UnicodeString __fastcall MyAdd(UnicodeString a, UnicodeString b);
#endif
template <typename T> T __fastcall MyAdd(T a, T b);
};
#ifdef TRY_TO_OVERRIDE_TEMPLATE
template <typename T> UnicodeString __fastcall MyAdd(UnicodeString a, UnicodeString b) {
int intA = a.ToInt();
int intB = b.ToInt();
return UnicodeString(a + b);
}
#else
UnicodeString __fastcall MyAdd(UnicodeString a, UnicodeString b) {
int intA = a.ToInt();
int intB = b.ToInt();
return UnicodeString(a + b);
}
#endif
template <typename T> T __fastcall MyMath::MyAdd(T a, T b) {
return a + b; // When defined DO_NOT_EXPLICITLY_REFERENCE_TEMPLATE, this gives standard error concatinating UnicodeStrings ([bcc32c Error] Unit1.cpp(41): invalid operands to binary expression ('const wchar_t *' and 'const wchar_t *')
}
void __fastcall TForm1::cmdRunClick(TObject *Sender)
{
UnicodeString txt;
MyMath * mth = new MyMath();
ComboBox1->Items->Add(L"1 + 3 =" + UnicodeString(mth->MyAdd<int>(1, 3)));
ComboBox1->Items->Add(L"1.1 + 3.3 =" + UnicodeString(mth->MyAdd<double>(1.1, 3.3)));
ComboBox1->Items->Add(L"2.2 + 4 =" + UnicodeString(mth->MyAdd<UnicodeString>(L"2.2", L"4"))); // result is "2.24" rather than "6"
#ifdef DO_NOT_EXPLICITLY_REFERENCE_TEMPLATE
ComboBox1->Items->Add(L"2.2 + 4 =" + UnicodeString(mth->MyAdd(L"2.2", L"4")));
#endif
}
You can rely on standard overloading rules. If you want a specific Add for Unicode strings then provide an overload next to the generic template you already have, and it will be selected at compile time.
#include <type_traits>
#include <string>
#include <iostream>
#include <format>
using namespace std::string_literals;
template<typename type_t>
auto add(const type_t& lhs, const type_t& rhs)
{
std::cout << "Generic add : " << lhs << " + " << rhs << "\n";;
return lhs + rhs;
}
// you can have non-template overloads too
// they will be selected in favor of the template
// when they match.
auto add(const std::string& lhs, const std::string& rhs)
{
auto result = std::format("String addition : '{}' + {}", lhs, rhs);
std::cout << result << "\n";
return result;
}
int main()
{
add(1, 2);
add("one"s, "two"s);
return 0;
}