成员变量和构造函数依赖于模板参数。

5
在C++11中,我想在一个类中有一个成员变量,并且只有在选择了它的默认模板值时才有构造函数进行初始化(当然仅对支持的类型如int)。
有哪些推荐的方法可以实现这一点(允许使用boost)?
类似于:
```cpp template class MyClass { //... private: T member_; }; ```
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
};

或者换一种说法:为了进行尺寸和速度优化,如果选择了模板默认值之外的另一个值,则我希望使用编译时常量而不是存储在成员变量中的值。
--
这里有一个例子,让一切都更清晰:
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!
};

这部分解决了问题:
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()
};

那么 C 的构造函数呢?还有其他更好的解决方案吗?

3个回答

5

只是一个想法,但也许会有所帮助:你可以尝试仅针对最小的差异使用基类,并"伪造"成员变量以便在它不存在时允许其余部分编译:

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

但正如我所说,这只是一个想法...


哦,那个“using”技巧可能真的有用,谢谢!是否有其他替代方案,例如如果我不仅有一个参数像“_x”,而是“_x”和“_y”? - Thomas
@Thomas B有三个专业化方向?我知道这并不是很可扩展,但它取决于您使用案例的许多细节...恐怕我不知道任何简单而通用的解决方案。 - Daniel Frey
@Thomas,我把我的例子搞反了,请看编辑后的答案! - Daniel Frey

2

专业化是前进的道路:

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

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

假设我的 C 类(两种情况下)包含一些常见的其他成员和方法。那么我可能会从你建议的专业类派生,但我将不再能够访问它的构造函数。 - Thomas
2
@Thomas:换个方式做:让模板继承一个共同的基类。 - Kerrek SB

0
我在这件事上支持Kerrek SB的观点。将您的公共代码,即运行时缓冲区处理放在一个公共基类中,并创建两个派生类,一个用于静态大小的缓冲区类,另一个用于动态缓冲区类。或者更好的做法是,根据通用编码准则,使用组合。
    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_;
    };

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接