Hiding member functions in a template class

Can I hide some member functions in a template class? 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 goal is to use this class so that in some cases we see only the increment () function and in some other cases we see only the increment (T) member function. To do this, I can think of 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, for example:

 Increment<long, MultipleIncrement> 

However, the compiler does not allow me to do this. Is there any other way in which this is possible? Will it work if the member function is actually a constructor?

+7
source share
3 answers

In this case, I would prefer to use specialized specialization. Would that 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; } }; 
+3
source

The template specialization is good. Inheritance sounds better. Have you looked at patterns in an inherited base class? (Or is it now considered 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); } 
+1
source

Here is the MWE, 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 (*) } 

Exit

Using c++ (Debian 6.2.1-5) 6.2.1 20161124 , we get:

 47.11 42 43 

Development

We need to set up 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() ... 

since this fails when creating the template instance dummy<T, single_increment> instead of failing to replace dummy<T, single_increment> the template parameters .

In addition, we want the user to be able to use methods without actually providing a method template parameter. Therefore, we make the default template parameter of the _Q method equal to Q

Finally, to actually cause a compiler error when using an unwanted method even when providing a method template parameter, only enable_if_t method if the _Q method template parameter is actually the same type as the corresponding Q template template parameter.

0
source

All Articles