Параметры шаблона по умолчанию и частичная специализация - PullRequest
0 голосов
/ 03 мая 2020

Я пытаюсь понять частичную специализацию шаблона с аргументами по умолчанию. Если я удаляю приведение к пустоте в специализации is_comparable, напечатанное значение всегда ложно, в то время как, если я оставлю приведение к (void), все будет работать нормально. Может кто-нибудь объяснить, почему нужен бросок на пустоту? Вероятно, это связано с сопоставлением аргумента шаблона по умолчанию для T3, но я пытаюсь получить здесь некоторые дополнительные сведения о предостережениях с частичной специализацией шаблона и параметрами шаблона по умолчанию.

template<typename T1, typename T2, typename T3 = void>
struct is_comparable
{
 static const bool value = false;
};

template<typename T1, typename T2>
struct is_comparable<T1, T2, decltype((void)(std::declval<T1>() == std::declval<T2>()))>
{
  static const bool value = true;
};

int main()
{
   cout << boolalpha;
   cout << is_comparable<int, char>::value << endl;
   cout << is_comparable<int, float *>::value << endl;
}

Обновление: я наблюдаю такое же поведение, даже когда используются указатели. Я бы предположил, что частичная специализация будет выбрана в этом случае?

template<typename T1, typename T2, typename T3 = void>
struct is_comparable
{
 static const bool value = false;
};

template<typename T1, typename T2>
struct is_comparable<T1*, T2*, decltype((std::declval<T1>() == std::declval<T2>()))>
{
  static const bool value = true;
};

int main()
{
   cout << boolalpha;
   cout << is_comparable<int*, int*>::value << endl;
}

Ответы [ 2 ]

0 голосов
/ 03 мая 2020

Мы используем основной шаблон по умолчанию, поэтому

  • is_comparable<int, char> равно is_comparable<int, char, void>
  • is_comparable<int, float *> равно is_comparable<int, float*, void>
  • is_comparable<int*, int*> равно is_comparable<int*, int*, void>

В настоящее время ваша специализация без применения пустоты в большинстве случаев (если только специальная перегрузка operator==) не равна

  • is_comparable<T1, T2, bool /* with SFINAE */>

Так что не соответствует ожидаемым параметрам. Вы должны будете использовать:

  • is_comparable<int, char, bool>
  • is_comparable<int, float *, bool>
  • is_comparable<int*, int*, bool>

Другой способ привести к void is std::void_t:

template<typename T1, typename T2, typename Enabler = void>
struct is_comparable : std::false_type {};

template<typename T1, typename T2>
struct is_comparable<T1, T2,
                     std::void_t<decltype(std::declval<T1>() == std::declval<T2>())>>
    : std::true_type {};
0 голосов
/ 03 мая 2020

Компилятор создает экземпляр первичного шаблона и получает следующее:

is_comparable<int, char, void>

Затем, чтобы выбрать наилучшее соответствие, он пытается создать экземпляр вашей специализации (при условии, что нет типа tyastast void и что замена типа выполняется успешно) и получает следующий тип:

is_comparable<int, char, bool>

Он не соответствует первичному шаблону вообще, поэтому не может быть лучшего соответствия.

...