Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

multiple functions with same name but different argument types as template parameter

Tags:

c++

c++11

I'm using xsd to create c++ code from a xml schema file. For a xml type multiple functions are created (for serialization etc).
If the type is called XmlType multiple functions of the following form are created:

XmlType XmlType_(const XmlType& a, const string& b)
string XmlType_(const XmlType& a)
...

This are normal functions and not members of XmlType and they all have the same name. For XmlType2 the functions would be called XmlType2_.

I would like to write a utility template class for all the different xml types of my xml scheme. The different functions are going to be called insight this class. What I have so far is something like this:

template<typename T>
using TFunc1 = T (*)(const T&, const string&);
template<typename T>
using TFunc2 = string (*)(const T&);

template<typename T, TFunc1<T> func2, TFunc2<T> func2>
class XmlUtil {
... 
}; 

When create an instance of the XmlUtil class if have to do it like this:

XmlUtil<XmlType, XmlType_, XmlType_> util; 

This feels a bit redundant and gets worse, when I have to pass more functions as parameters.

I would like to use the util class like this:

XmlUtil<XmlType, XmlType_> util; 

or even better like this

XmlUtil<XmlType> util; 

The only way I can think of is to somehow use define, but it doesn't feel right.
Is there an other way to do this?

EDIT: I'm using a define now:

#define TRPL(name) name, name ## _, name ## _
...
XmlUtil<TRPL(XmlType)> util;

I'll edit this, if I find something better (maybe override sets like Yakk suggested in his answer).

like image 715
guini Avatar asked Oct 03 '22 13:10

guini


2 Answers

This:

XmlUtil<XmlType> util;

is impossible because there is no way to get from XmlType to XmlType_. Their relationship is discarded after the automatic code generator.

However this:

XmlUtil<XmlType_> util;

may be possible. You can deduce the function type of XmlType_ and then use the deduced return type which will be XmlType. I believe there are standard library function for this purpose.

As for the two different overloads, that may be trickier. I do not think that you can pass a function overload set as a template parameter, the resolution is done on the template argument in the context of the template parameter to one function. I don't think there is a way to defer this action without using the preprocessor.

So I would argue that you should use a #define. It is better than nothing.

like image 141
Andrew Tomazos Avatar answered Oct 11 '22 13:10

Andrew Tomazos


This looks like a job for override sets.

static struct foo_override_set_type {
  template<typename... Args>
  auto operator()( Args...&& args ) const
  ->
    decltype( foo( std::forward<Args>(args)... ) )
  {  return ( foo( std::forward<Args>(args)... ) ); }
  template<typename T>
  operator T() { return foo; }
} foo_override_set;

Objects of type foo_override_set_type represent the entire override set of foo. Calling them with operator() does an override set lookup on foo and calls the resulting function. Casting them to a function pointer does the same thing as casting the token foo to a function pointer (or other value).

Your code generation can auto-generate such override set types. It can also make a traits class that maps from your type XmlType to the override set of XmlType_ functions via specialization.

Then, your XmlUtil<XmlType> can access the override set of XmlType_ via that traits class. It first instantiates the override set variable, then invokes () on it.

As an aside, @Xeo has a proposal to make creating such objects as easy as typing []XmlType_ in C++1y or C++1z.

like image 39
Yakk - Adam Nevraumont Avatar answered Oct 11 '22 15:10

Yakk - Adam Nevraumont