【问题标题】:Hiding member functions in a template class在模板类中隐藏成员函数
【发布时间】:2011-04-20 19:12:25
【问题描述】:

是否可以在模板类中隐藏一些成员函数? 假设我们有类似的东西:

template <class T>
class Increment
{
public:
    void init(T initValue)
    {
         mValue = initValue;
    }  

    T increment()
    {
        ++mValue;
    }

    T increment(T delta)
    {
        mValue += delta;
    }
private:
    T mValue;
};

目标是在某些情况下以某种方式使用此类 我们只看到 increment() 函数,在其他一些情况下 我们只看到 increment(T) 成员函数。 为此,我可以考虑使用 SFINAE:

class MultipleIncrement
{
    typedef int MultipleIncrement_t;
};

class SingleIncrement
{
    typedef int SingleIncrement_t;
};

template <class T, class Q>
class Increment
{
public:
    void init(T initValue)
    {
        mValue = initValue;
    }

    T increment(typename Q::SingleIncrement_t = 0)
    {
        ++mValue;
    }

    T increment(T delta, typename Q::MultipleIncrement_t = 0)
    {
        mValue += delta;
    }
private:
    T mValue;
}

然后使用我的模板,例如:

Increment<long, MultipleIncrement>

但是,编译器不允许我这样做。 还有其他可行的方法吗? 如果成员函数实际上是构造函数,它也可以工作吗?

【问题讨论】:

  • 出于兴趣,您使用的是什么编译器?

标签: c++ templates hide sfinae


【解决方案1】:

在这种情况下,我更喜欢使用模板专业化。这样的事情对你有帮助吗?

struct SingleIncrement;
struct MultipleIncrement;

template <
    class T, 
    class Policy = SingleIncrement // default template param
>
class Increment
{
    T mValue;
public:
    Increment(T initValue)
    :   mValue(initValue)
    {}

    T increment()
    {
        ++mValue;
    }
};

// template specialization for MultipleIncrement
template <class T>
class Increment<T,MultipleIncrement>
{
    T mValue;
public:
    Increment(T initValue)
    :   mValue(initValue)
    {}

    T increment(T delta)
    {
        mValue += delta;
    }
};

【讨论】:

  • 确实是一种方法;问题是“init”不是唯一必须初始化的成员函数;恰恰相反,有很多常见的功能会被重复,除非我开始考虑继承......
  • 我会尝试利用继承来避免重新实现通用函数,然后使用模板特化来使用正交类型。
  • MultipleIncrement 的模板特化声明如下:template&lt;class T&gt; class Increment&lt;T,MultipleIncrement&gt; {...}
【解决方案2】:

模板专业化很好。继承听起来更好。您是否考虑过在继承的基类上进行模板化? (或者这现在被认为是假的?)

#define SHOW(X)  cout << # X " = " << (X) << endl

template <class T>
class A
{
public:
  void foo(T t) {SHOW(t); }
};

template <class T, class BASE>
class B : public BASE
{
public:
  void bar(T t) {SHOW(t); }
};

int
main()
{
  B<int,A<int> > b;
  b.foo(1);
  b.bar(2);
}

【讨论】:

    【解决方案3】:

    这里是如何实现这一点的 MWE:

    #include <iostream>
    
    using namespace std;
    
    struct multi;
    struct single;
    
    template<class T, class Q>
    struct dummy {
      dummy(T value) : m_value(value) { }
    
      // using enable_if_t in template argument
      template<class _Q = Q, enable_if_t<is_same<_Q, single>::value && is_same<_Q, Q>::value, int> = 1>
      T increment() { return ++m_value; }
    
      // using enable_if_t in method return type
      template<class _Q = Q>
      enable_if_t<is_same<_Q, multi>::value && is_same<_Q, Q>::value, T>
      //enable_if_t<is_same<_Q, multi>::value, T> // (*)
      increment(T delta) { return (m_value += delta); }
    
      T m_value;
    };
    
    int main() {
      dummy<double, multi> m(47.10);
      //cout << m.increment() << endl; // error as expected
      cout << m.increment(.01) << endl;
    
      dummy<int, single> s(41);
      cout << s.increment() << endl;
      cout << s.increment<single>() << endl;
      //cout << s.increment(1) << endl; // error as expected
      //cout << s.increment<multi>(1) << endl; // not an error when using (*)
    }
    

    输出

    使用c++ (Debian 6.2.1-5) 6.2.1 20161124 会产生:

    47.11
    42
    43
    

    细化

    我们需要对方法进行模板化,以使 SFINAE 能够正常工作。我们不能使用类似的东西

    std::enable_if_t<std::is_same<_Q, multiple_increment>::value, T> increment() ...
    

    因为在实例化模板dummy&lt;T, single_increment&gt;时失败,而不是在替换方法模板参数时失败。

    此外,我们希望用户能够在不实际提供方法模板参数的情况下使用这些方法。所以我们让方法模板参数_Q默认为Q

    最后,即使在提供方法模板参数的情况下,为了在使用不需要的方法时真正强制编译器错误,我们只enable_if_t该方法如果方法模板参数_Q实际上与相应的类模板参数@相同类型987654330@.

    【讨论】:

      猜你喜欢
      • 2021-12-26
      • 1970-01-01
      • 2017-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-02
      • 1970-01-01
      • 2021-11-17
      相关资源
      最近更新 更多