Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

member variable and constructor dependent on template parameter

In C++11, I'd like to have a member variable in a class and a constructor for its initialization only if its default template value was chosen (only for supported types like int, of course).

What are recommended ways to achieve this (boost allowed)?

Something like:

template< int _x = -1 > struct C {
    C() {} // only available if _x != -1
    C( int x ) : x( x ) {} // only available if _x == -1
    // more methods that are common for all _x and refer to _x / x
    private:
    int x; // only available if _x == -1
    // more members that are common for all _x
};

Or, put in another way: For size and speed optimization, I would like to use a compile time constant instead of a value stored in a member variable if another value than the template default was chosen.

--

Here is an example to make everything clearer:

template< int _size = -1 > struct Block {
    Block() { buf = mmap( _size, ... ); } // exists only when size!=-1
    Block( int s ) { buf = mmap( size = s, ... ); } // exists only when size==-1
    ~Block() { munmap( buf, getSize() ); } // should use the correct size
    int getSize() const { return ???; } // gets _size if !=-1, size otherwise
    // other methods that use buf and getSize()
    private:
    void *buf;
    const int size; // only exists for size == -1!
};

This solves it partially:

template< int _x > struct X {
    int getX() const { return _x; }
};
template<> struct X< -1 > {
    X( x ) : x( x ) {}
    int getX() const { return _x; }
    private:
    int x;
};

template< int _x = -1 > struct C : X< _x > {
    C() {} // only available if _x != -1
    C( int x ) : X< _x >( x ) {} // only available if _x == -1
    // more methods that are common for all _x and use this->getX()
};

But what about the constructors of C, and are other / nicer solutions available?

like image 594
Thomas Avatar asked Apr 08 '13 18:04

Thomas


2 Answers

Just an idea, but maybe it helps: You could try to use a base class only for the minimal differences and "fake" the member variable for when it's not there to allow the rest to compile:

template< int _x > class B
{
public:
  B() {}
protected:
  static const int x = _x;
};

template<> class B< -1 >
{
public:
  B( int i ) : x( i ) {}
protected:
  int x;
};

template< int _x = -1 >
class C : public B<_x>
{
public:
  using B<_x>::B; // inherit B's ctors

  void f()
  {
    if ( x == ... ) // uses either the member variable x or the static const int x!
  }
};

but as I said, it's just an idea...

like image 66
Daniel Frey Avatar answered Nov 15 '22 08:11

Daniel Frey


Specialization is the way to go:

template <int N> struct C
{
    C(int n) : n_(n) { }
    int n;
};

template <> struct C<-1>
{
    C() { }
    C(int n) : n_(n) { }
    int n;
};
like image 24
Kerrek SB Avatar answered Nov 15 '22 07:11

Kerrek SB