There are two "C" functions:
void fooA(const char*); void fooW(const wchar_t*);
Then there is a wrapper template function:
template<typename _TChar> void foo(const _TChar* str) { // call fooA or fooB based on actual type of _TChar // std::conditional .. ? // fooA(str); // fooW(str); }
If the caller calls foo("Abc")
, this template function should make a compile-time call to fooA
. Similiarly, foo(L"Abc")
should make the final call to fooW
.
How do I do that? I thought of using std::conditional
but couldn't make it.
I cannot make fooA
or fooB
overloaded, since these are C functions.
Defining a Function TemplateA function template starts with the keyword template followed by template parameter(s) inside <> which is followed by the function definition. In the above code, T is a template argument that accepts different data types ( int , float , etc.), and typename is a keyword.
A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.
A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)
main cannot be a function template; it must be a function.
You can put all your wchar_t
versions in a class template, say overloads
and their char
counter-parts in its specialization as shown below:
template<typename WideCharVersion> struct overloads { void foo(wchar_t const * arg) { FooW(arg); } //more wchar_t functions }; template<> struct overloads<std::false_type> { void foo(char const * arg) { FooA(arg); } //more char functions }; //a friendly alias! template<typename T> using is_wide_char = typename std::is_same<whar_t, T>::type;
And then you can use them as:
template<typename _TChar> void foo(const _TChar* str) { overloads<is_wide_char<_TChar>>::foo(str); }
Other way is to use Expression SFINAE which does not require to you write anything like overloads
and does the same job with less code:
template<typename _TChar> void foo(const _TChar* str) { invokeOne(fooA, fooW, str); }
And then you can implement invokeOne
as:
template<typename F1, typename F2, typename ... Args> auto invokeOne(F1 f1, F2 f2, Args && ... args) -> decltype(f1(args...)) { return f1(args...); } template<typename F1, typename F2, typename ... Args> auto invokeOne(F1 f1, F2 f2, Args && ... args) -> decltype(f2(args...)) { return f2(args...); }
Have a look at the online demo.
In this approach, you don't have to add the overloads to the overloads
class template and to its specialization. Instead you just pass them as arguments to invokeOne
which calls the right overload for you.
Hope that helps.
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