Приоритезация специализации класса

Скажем, у нас есть двойной параметризованный шаблон, например

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

и что существуют специализации для конкретного A и конкретного B

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

Теперь, когда мне нужно создать экземпляр Class<A1,B1>, компилятор жалуется на двусмысленность, так как он находит <A,B1> и <A1,B> одинаково полезными.

Конечно, проблему можно устранить, добавив специализацию <A1,B1>, но в моем контексте она будет идентичной <A1,B>.

Есть ли способ устранить двусмысленность, не повторяя полный <A1,B> полный код?

Ответ 1

Одна из возможностей - просто запретить выбор второй специализации:

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

Демо.

Ответ 2

Я добавлю третий параметр по умолчанию в базовый шаблон и разрешаю каждую специализацию подбирать через 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();
}

Пример

или даже проще (в зависимости от того, приемлемо ли это в ваших случаях использования):

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

Пример

Ответ 3

Отказ от ответственности: я его не тестировал, и я отнюдь не эксперт по шаблонам.

Моя идея: дайте дублированной специализации имя, поэтому вы можете обратиться к нему:

template<class B> classA1 { ... }; // code goes here.

template<class B> class Class<A1,B> : public classA1<B> {};
template<> Class<A1,B1> : public classA1<B1> {};