简体   繁体   中英

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?

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

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;
};

I'm with Kerrek SB on this one. Put your common code, namely the runtime buffer handling in a common base class an create two derived classes, one for your statically sized buffer class and one for your dynamic buffer class. Or better yet, according to common coding guidelines , use composition.

    class buffer_impl {
    public:
        buffer_impl(int size) : data_ {mmap( size, ... )}, size_ {size} {}
        ~buffer_impl() { munmap( data_, getSize() ); }
        int getSize() const noexcept { return size_; }

        // other buffer routines
        // ...
    private:
        void* data_;
        int size_;
    };

    template <int _size = -1 >
    class buffer {  // static size
    public:
        buffer() : impl_ {_size} {}
        static constexpr int getSize() noexcept { return _size; }
    private:
        buffer_impl impl_;
    };

    template <>
    class buffer<-1> {  // dynamic size
    public:
        buffer(int size) : impl_ {size} {}
        int getSize() const noexcept { return impl_.getSize(); }
    private:
        buffer_impl impl_;
    };

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM