Hiding member functions in a template class

Is it possible to hide some member functions in a template class? Let's imagine we have something like:

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

    T increment()
    {
        ++mValue;
    }

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

The objective is to use this class in a way that, in certain cases we only see the increment() function and in some other cases we only see the increment(T) member function. To do that, I can think about something with 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;
}

And then use my template like, for example:

Increment<long, MultipleIncrement>

However, the compiler is not letting me do this. Is there any other way in which this is feasible? Would it also work if the member function is actually the constructor?


In this case, I would prefer using template specialization. Would something like this help you?

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

Template specialization is good. Inheritance sounds better. Have you considered templating on the inherited base class? (Or is this now considered a faux pax?)

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

Here is a MWE of how this could be achieved:

#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 (*)
}

Output

Using c++ (Debian 6.2.1-5) 6.2.1 20161124 this yields:

47.11
42
43

Elaboration

We need to template the methods to make SFINAE work at all. We cannot use something like

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

because that fails when instantiating the template dummy<T, single_increment> instead of failing when substituting method template parameters.

Further, we want the user to be able to use the methods without actually providing a method template parameter. So we make the method template parameter _Q default to Q .

Finally, to really force a compiler error when using the unwanted method even when providing a method template parameter, we only enable_if_t the method if method template parameter _Q is actually the same type as the respective class template parameter Q .

链接地址: http://www.djcxy.com/p/52070.html

上一篇: OSGi的指导原则,经验,技巧等

下一篇: 在模板类中隐藏成员函数