【问题标题】:Arranging Class Structure at Compile Time according to Template Parameters在编译时根据模板参数排列类结构
【发布时间】:2011-11-14 04:03:55
【问题描述】:

在 C++ 中是否可以根据模板参数包含/排除成员变量?

这是一个例子:

template< class T >
class RealNumber
{
    T real;
};

template< class T >
class ComplexNumber
{
    T real;
    T imag;
};

由于它们有许多共同的属性,只有一个类来表示一个数字(带有额外的模板参数)可以防止一些代码重复。

我想做的事情是这样的

template< class T , class U >
Number
{
    T real;

    // If U is not void
    U imag;
}

所以如果第二个参数为 void,就不会有名为 imag 的成员,产生:

sizeof( Number< T , void > ) == sizeof( T )

我尝试了 enable_if 但没有得到任何结果。

如果这不可能,是否有任何黑客可以使这成为可能?

【问题讨论】:

  • 你可以把它设为Number&lt;T&gt; 并根据T 是基本的还是std::pair&lt;U,W&gt; 进行分支。
  • Boost 有一个您可能感兴趣的压缩对类型。我相信它被称为compressed_pair
  • @DennisZickefoose 我试过compressed_pa​​ir,效果很好。虽然它只能使一个变量包含/排除,但它可以被黑客攻击以使其包含多个变量。我会调查的。谢谢你的回答。

标签: c++ templates compile-time enable-if


【解决方案1】:
typedef NullType struct {} NullType;
template< class T , class U = NullType>
class Number
{
  T real;
  U image;
}

【讨论】:

    【解决方案2】:

    检查继承技巧是否适合您:

    template<class T, class = void >
    class RealNumber
    {
      protected: T real;
    };
    
    template<class T, class U>
    class ComplexNumber : public RealNumber<T>
    {
      U imag;
    };
    

    【讨论】:

    • 对不起,这不是我想要的。
    • @MustafaSerdarŞanlı,这种方法有什么问题。你当然不能做你在问题中提出的问题。因为,考虑一个简单的场景:如果Uvoid 那么包含它的方法会发生什么?可以发现许多这样的缺陷。在上面的解决方案中,您可以系统地解决您的问题。
    • 如果我不能肯定地做我在问题中提出的问题,那么请写另一个答案并解释原因,我会接受这个答案。我想要一个名为 Number 的类,它可以有一个或两个基于模板参数的成员变量。但是在您的示例中,我必须为我不想要的变量使用两个不同的类名。
    【解决方案3】:

    此答案不完整,仅说明如何使用enable_if 进行类模板的特化。

    template<class T,class U,class Enable = void>
    class Number
    {
      T real;
      T imag;
    };
    template<class T,class U>
    class Number<T,U,typename std::enable_if<std::is_void<U>::value>::type>
    {
      T real;
    };
    

    具体实施取决于问题的确切性质。 比如,

    • 如果允许 RealNumber 到 ComplexNumber 的转换(即is_a 关系),您可以考虑从一种实现继承到另一种实现。
    • 要重用大量属性,可以在私有基类中实现公共部分。
    • 根据具体问题,可以检查是否真的需要模板参数U。此外,实数Number&lt;int,void&gt;Number&lt;int&gt; 的首选语法应该是什么。等

    【讨论】:

    • 我在 g++ 中测试了你的代码,它可以工作,但有一个问题,Number&lt; int , int &gt;Number&lt; int , int , void &gt; 都有 8 字节大小,虽然第二个没有 imag 变量。我想要实现的是sizeof( Number&lt; int , int , void &gt; ) == 4
    • @Mustafa:也许你会更好地陈述你的问题,而不是你的解决方案?
    【解决方案4】:

    很难说你在哪里开车,但这里有一个粗略的骨架:

    template <typename T> class Number
    {
      template <typename S> class Adder
      {
        typedef S type;
        static type add(type a, type b) { return a + b; }
      };
      template <typename U, typename W> class Adder<std::pair<U,W>>
      {
        typedef typename std::pair<U,W> type;
        static type add(type a, type b) { return type(a.first + b.first, a.second + b.second); }
      };
    
      T val;
    
    public:
      T operator+(const T rhs) { return Adder<T>::add(val, rhs); }
    };
    

    请注意,大多数标准库数值函数已经为 std::complex 类型重载,因此您可能需要考虑一下是否真的需要自己编写。

    用法:Number&lt;int&gt;Number&lt;double&gt;Number&lt;std::pair&lt;double, double&gt;&gt;

    【讨论】:

    • 其实我想做的不是做一个 Number 类。我写了这个例子来轻松展示我想要实现的目标。您的示例对我不起作用,因为我希望能够包含/排除多个变量。
    猜你喜欢
    • 1970-01-01
    • 2019-10-18
    • 1970-01-01
    • 2013-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多