Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prioritizing class specializations

Tags:

c++

c++11

Let's say we have a dual parametrized template like

template<class A, class B>
class Class { .... };

and that there are specializations for a particular A and a particular B

template<class B> class Class<A1,B> { .... };
template<class A> class Class<A,B1> { .... };

Now, when I have to instantiate Class<A1,B1> the compiler complains for ambiguity since it find <A,B1> and <A1,B> equally usable.

The problem can of course be eliminated by adding an <A1,B1> specialization, but -in my context- it will be identical <A1,B>.

Is there a way to eliminate the ambiguity without repeating the entire <A1,B> full code?

like image 793
Emilio Garavaglia Avatar asked Nov 10 '14 10:11

Emilio Garavaglia


2 Answers

One possibility is to simply forbid the second specialization to be selected:

template<class A, class B, class=void>
class Class {};

template<class B>
class Class<A1,B> {};

template<class A>
class Class<A, B1, typename std::enable_if<!std::is_same<A,A1>::value>::type> {};

Demo.

like image 116
Columbo Avatar answered Oct 23 '22 07:10

Columbo


I'd add a third default parameter to the base template and allow each specialization to be picked up through SFINAE:

template<class A, class B, 
         class extra = void /* Enable/disable specialization through SFINAE */>
class Class { public: void hello() {std::cout << "Base" << std::endl;} };

template<class B> class Class<A1, B> { 
 public: 
 void hello() {std::cout << "First" << std::endl;} 
};
template<class A> class Class<A, B1, 
                   typename std::enable_if<!std::is_same<A, A1>::value>::type> {
  public: 
  void hello() {std::cout << "Second" << std::endl;} 
};

int main()
{     
  Class<A1,B1> obj;// The first one is picked up
  obj.hello();
  Class<A,B1> obj2; // The second one is picked up
  obj2.hello();
  Class<A,B> obj3; // Base
  obj3.hello();
}

Example

or even simpler (depending if it's acceptable in your use cases):

template<class A, class B, bool AisA1 = std::is_same<A,A1>::value>
class Class { public: void hello() {std::cout << "Base" << std::endl;} };

template<class B> class Class<A1, B, true /* Pick this when A == A1 */> { 
 public: void hello() {std::cout << "First" << std::endl;} 
};
template<class A> class Class<A, B1, false> { 
 public: void hello() {std::cout << "Second" << std::endl;} 
};

Example

like image 24
Marco A. Avatar answered Oct 23 '22 05:10

Marco A.