Friday, April 15, 2011

Fun with C++ templates and generic insertion/extraction operator overloading

Recently, I ended up with a class hierarchy of business objects which was generated by a tool. One objective for me was to support the easy serialization and deserialization of these classes. The tools generating these classes provided some c library functions for that matter but what I really wanted is proper C++ insertion/extraction operator support. The users of the code shall be able to write something like this:

xsd__base64Binary binary; // a generated business object
binary.id = "a value";

// printing an (xml-based)
// version of the object to stdout:
std::cout << binary;


Likewise, the deserialization of objects from a given input stream shall work accordingly.

For this to happen we simply have to define overloaded operators implementing the custom streaming into an output stream and from an input stream. As the only commonality of all the classes was a public member variable called "soap", I decided to implement the operators as template functions and created a new header file for those:

template<typename T>  std::ostream&
operator<<(std::ostream &o, const T&p)
{
// C-serializer function provided
// by the toolkit
soap_serialize(p.soap);
return o;
}

template<class T>std::istream &
operator>>(std::istream &i, T &t)
{
soap_begin_recv(t.soap);
soap_end_recv(t.soap))

return i;
}


I wrapped the given C serializer functions, included my new header file and tried the code. At first it looked great but when I added more code...

std::cout << "Success!";


... my compiler greeted me with the following error:

1>test.cpp(123): error C2593: 'operator <<' is ambiguous
1> customoperators.h(109): could be 'std::ostream &operator <<<const char[9]>(std::ostream &,T (&))'
1> with
1> [
1> T=const char [9]
1> ]
1> c:\programme\microsoft visual studio 10.0\vc\include\ostream(851): or 'std::basic_ostream<_Elem,_Traits> &std::operator <<<char,std::char_traits<char>>(std::basic_ostream<_Elem,_Traits> &,const _Elem *)' [found using argument-dependent lookup]
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]

What just happened is that we inadvertently introduced an ambiguity with certain template based streaming operators already predefined for us. The compiler cannot decide on which version of the operator to use and thus gives up with an error. (Nontemplate operators on the other hand should still be fine as the language prefers those overloads over template versions.)

Amazingly, it is still possibly to relax the situation by using the full power of template metaprogamming. Even though function templates do not support partial spezializations, it's still possible to come up with constructs where the compiler will ignore our newly introduced operators when feasible. The following section will highlight, how it's possible to let the compiler consider the operator if and only if objects of the given type parameter T contain a member named "soap". As our business objects lack any common interface beside this very member, it's clear that there may still be scenarios where this could lead to undesired results anyways. But as we're in full control of the source code then, it's much easier to work around further problems.

The first construct which helped me on my way was the enable_if family of templates introduced with the great boot c++ libraries. These template expressions are using the so called SFINAE principle (subsitution failure is not an error) to their great advantage. SFINAE comes into play when the compiler tries to substitute template parameters and ends up with an invalid type or expression. Instead of bailing out with a compiler error, the affected template construct is simply not considered as legal match for the actually used type parameters. By exploiting this fact, enable_if allows the specific inclusion or exclusion of templates into the set considered by the compiler. The basic construct given in boost is deceptively short and elegant:

template <bool B, class T = void>
struct enable_if_c {
typedef T type;
};

template <class T>
struct enable_if_c<false, T> {};


The template struct enable_if_c has a boolean type parameter B and a type parameter T. T is typedefed inside the struct and exposed by the name type. A partial specialization of enable_if_c for the concrete boolean value of false misses this type. When other templates are now referring to type inside enable_if_c, they will only be valid if the boolean compile time expression for B is evaluated to true. If this is not the case, enable_if_c::type is an invalid construct, SFINAE kicks in and the template relying on enable_if_c will be kicked out of the set of templates considered by the compiler.

SFINAE can be employed to gather a variety of useful information about a type. The paper Once, Weakly: SFINAE Sono Buoni describes a variety of use cases. I've taken out one example for my basic problem: when is a given type T actually a class type?


template<typename T>
struct IsClass
{
typedef char True ; //sizeof(True)==1
typedef struct{char a[2];} False; //sizeof(False)>1

template<class C>static True isClass(int C::*);
template<typename C>static False isClass(...);

enum
{
value = sizeof(isClass<T>(0))==sizeof(True)
};
};


This struct template uses the different sizes of the two member template functions and the C sizeof() operator to gather, whether T is a class or not. If T is a clas, the size of the return value of isClass(0) will be sizeof(True) as the first overloaded can be called. Else the generic (lowest priority) overload for variable arguments will be taken, resulting in a different return type and thus a different evaluation for value.

This basic idea of using the sizeof operator on the return types of overloaded template function can also be extended to gather, whether a given type has a certain member. The following construct is adapted from here and here and returns just that. Instead of going over the construct myself, I'm delegating the interested reader towards Cplusplus.co.il which already has a great walkthrough of the basic ideas.


template<typename T, typename Enable = void>
struct HasSoap {
struct Fallback {
int soap;
}; // introduce member name "soap",
// possibly creating an ambiguity

struct Derived : T, Fallback { };

template<typename C, C>
struct ChT;

template<typename C>
static char (&f(ChT<int Fallback::*, &C::soap>*));

template<typename C>
static int (&f(...));

static bool const value =
sizeof(f<Derived>(0)) == sizeof(int);
};


I had to add an additional partial class template specialization to make sure non class types can be used with HasSoap too. (Otherwise the compiler would complain that it can't derive from a non-class type):


// partial specialization: non class types have no soap member and can't be derived from.
template<typename T>
struct HasSoap<T, typename Enable_If_C<!IsClass<T>::value>::type>
{
static bool const value = false;
};


With all these additional templates in place there was still one thing to do: adapt my operators to be only considered when the given type has a "soap" member:
Changing the operator's signature from


template<typename T> std::ostream&
operator<<(std::ostream &o, const T&p)


to


template<typename T>
typename Enable_If_C<HasSoap<T>::value, std::ostream>::type&
operator<<(std::ostream &o, const T&p)


took care of this. What's happening now is, that HasSoap<T>::value will evaluate only to true for class types with soap members. If this is not the case, the Enable_If_C specialization without a type typedef will be chosen by the compiler, yielding an invalid reference to Enable_If_C::type. SFINAE kicks in again and the compiler is spared an unnecessary ambiguity.

Considering this little template adventure my conclusion for this post can only be: C++ Templates may be hard to understand sometimes but then again, they can provided us with really powerful ways to craft our source code.

Thursday, April 14, 2011

m2eclipse plugin: NoClassDefFoundError when running JUnit tests

We are using the m2eclipse plugin (including its WTP extension) for leveraging Maven integration in Eclipse. Recently, we ran into the issue of class not found errors, when trying to run JUnit tests from Eclipse (Run/Debug as JUnit test). More information about this problem can be found here, here or here.
A workaround has been suggested to change the build path order in Eclipse - i.e., moving the Maven Dependencies before the JRE System Library in the build order. However, this did not solve our problem.

We discovered that the auto-clean feature of the maven-clean-plugin caused the troubles in our setting, which we used as follows in the pom:


<plugin>    
  <artifactId>maven-clean-plugin</artifactId>    
  <version>2.4</version>    
  <executions>      
    <execution>           
      <id>auto-clean</id>        
      <phase>initialize</phase>        
      <goals>          
        <goal>clean</goal>        
      </goals>      
    </execution>    
  </executions>  
</plugin>

After removing the maven-clean-plugin from our pom.xml, running JUnit tests from a m2eclipse project worked like a charm.