5

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

5
  • This is C++11-specific, I believe? Commented Jul 12, 2013 at 12:04
  • Yes, I'm using c++11 (MinGW with gcc 4.8). Added the tag. Commented Jul 12, 2013 at 12:05
  • template specialization. Made an equivalent of Func<> (in c#) in c++ using it in which Execute had a template parameter specific implementation and argument count. By using default settings in the template you can chose to only define some of the type arguments. Commented Jul 12, 2013 at 12:12
  • There is no way to pass around the name of a family of overloaded functions. I can't think of any way to simplify this except with a macro. Commented Jul 12, 2013 at 12:29
  • @aschepler: you can make the family of overloaded functions static member functions of a utility class and then pass the enclosing type as a template argument. But I don't see how this is related to the question, since the functions share the same arguments but differ by name Commented Jul 12, 2013 at 12:42

5 Answers 5

3

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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.

2 Comments

Thanks for your suggestion. I don't fully understand it yet, but I will look into it. Do you maybe have a link to some documentation on override sets?
@guini No, not really. An override set is just an object that behaves "as if" it was a complete set of overrides of some function name syntactically. You can do this with perfect forwarding and a template<T> operator T pretty well. You can read up on perfect forwarding (the C++11 technique that I use above in operator()) which can make it make more sense. The operator T exists so you can assign an override set to a function pointer and have it extract the property override "magically". And because it is a stateless object, you can pass it or its type to where you need it.
0

Default template arguments in the class definition?

Like

template<typename T, TFunc1<T> func1 = XmlType_, TFunc2<T> func2 = XmlType_>
class XmlUtil {
    // ...
};

3 Comments

The name of the function depends on the type name. So I think this wouldn't work. I edited the question to make this clearer.
@guini I just tried it, and it seems to compile fine. Worth a shot to try?
If I understand correctly the function name XmlType_ is fixed in your example. But in my case the function name changes. If I have the type Type1 the function will be called Type1_, for Type2 it will be called Type2_ etc.
0

You can use a trait class like this

template <typename T>
struct Trait{
    typedef T type;
    typedef T (*func1)(const T&, const string&);
    typedef string (*func2)(const T&);
};

and make the class XmlUtil have one template parameter (let's name it Trait) and use Trait::type, Trait::func1 and Trait::func2. See here for full usage.

In the example, the type of XmlUtil goes like:

XmlUtil<Trait<XmlType> >

I've done it this way since I don't know well your problem. It might be the case that you can just define the Trait class right into XmlUtil and use

 XmlUtil<XmlType>

Other variations are possible, it just depend on what you need.

You can read a very brief introduction to trait classes here. If you want to read more about this topic I suggest you Modern C++ (Alexandrescu).

5 Comments

Thanks for your answer. I'll check it out. But I will need some time to understand it :-)
Re-reading the question and the answer I'm not sure I addressed your question properly, give me some feedback so that I can be of more help, if needed.
I'll check it out and comment again later. I'm not that experienced with templates and have to do some reading and thinking to understand your example. Thanks for ruining my weekend ;-)
This gives you the types of the two different XmlType_ functions, but it does not give you the functions themselves. The OP already has the types TFunc1 and TFunc2, your answer just shuffles them into typedef members of a template class, rather than standalone alias templates. This rearrangement makes no progress toward solving the OPs problem sorry.
Yes, I noticed I could have been solving the wrong problem later (as for my comment). I'm going to work this out later or delete the answer if I don't manage to. Thanks for reviewing
0

I am not sure I fully understand what you are asking. The common approach for serialization and deserialization would be to create a factory (abstract factory) and resolve the construction of the objects dynamically. Note that this can be improved for complex structures, where the code generator can create member functions to extract the exact type of each one of the members.

But again, I don't fully understand what you are really trying to do... As a recommendation I believe it would help if you provided more of a description of the problem to solve, as the question focuses on how to make your solution work, and that implicitly discards other approaches that might be better designs.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.