Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call function based on template argument type

Tags:

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.

like image 566
Ajay Avatar asked Nov 11 '16 10:11

Ajay


People also ask

How do you call a function in a template?

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.

Can a template parameter be a function?

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.

How do you use template arguments in C++?

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.)

Can we use template in main function?

main cannot be a function template; it must be a function.


1 Answers

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); } 

Expression SFINAE makes it easy!

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.

like image 107
Nawaz Avatar answered Oct 02 '22 13:10

Nawaz