Search code examples
c++c++11conditional-compilation

C++11: conditional compilation: members


I'm trying to make a struct with conditional members, that means, different members exists only with specific specializations. But, I want that this classes are fastest as possible. I've tried it in three differents ways:

Way 1:

 template<typename T, bool with_int = false>
 struct foo
 {
     template<typename... Args>
     foo(Args&&... args) : m_t(forward<Args>(args)...)
     {}

     T m_t;
 }

 template<typename T>
 struct foo<T, true>
 {
     template<typename... Args>
     foo(Args&&... args) : m_t(forward<Args>(args)...), m_id(0)
     {}

      T m_t;
      int m_id;
 };
  • Disadventage: repeated code for each specialization.

Way 2:

 template<typename T, bool with_int = false>
 struct foo
 {
     template<typename... Args>
     foo(Args&&... args) : m_t(forward<Args>(args)...)
     {}

     virtual ~foo() {}

     T m_t;
 }

 template<typename T>
 struct foo<T, false> : public foo<T>
 {
      using foo<T>::foo;

      int m_id = 0;
 };
  • Adventage: few code.
  • Disadventage: Use of vtables/inheritance/etc: more time in construction or access to members? But, in other way, I don't pretend to to use "references" to base class. What is it the real adventages or disadventages of this aproach?

Way 3

 using nil_type = void*;
 using zero_type = nil_type[0];

 template<typename T, bool with_int = false>
 struct foo
 {
    template<typename... Args, typename = typename enable_if<with_int>::type>
    foo(Args&&... args) : m_t(forward<Args>(args)...), m_int(0)
    {}

    template<typename... Args, typename = typename enable_if<!with_int>::type>
    foo(Args&&... args) : m_t(forward<Args>(args)...)
    {}        

    T m__t;
    typename conditional<with_int, int, zero_type>::type m_int;
 };
  • Ventages: Write code once; when with_int is false, field m_int has size 0 (almost with gcc 4.7.2).
  • Adventages: More use of templates (reduce readability) and I'm not sure about how compilers deal with member of size 0. I don't know indeed to what extent a size-0-field is dangerous or has sense. Repeated constructors, but perhaps this is avoidable.

What is the best approach or method?


Solution

  • Have you considered inheritance?

    template< bool >
    struct foo_int_base
    {
      // stuff without the int
      void f(); // does not use m_id
    };
    
    template<>
    struct foo_int_base< true >
    {
      // stuff with the int
      int m_id = 0;
      void f(); // uses m_id
    };
    
    template< typename T, bool with_int = false >
    struct foo : foo_int_base< with_int >
    {
      // common stuff here
    };