Почему void_t не работает в SFINAE, но enable_if делает

16

Я пытался понять, как работает SFINAE , и я экспериментировал с этим кодом

#include <type_traits>

struct One { 
  using x = int; 
};
struct Two { 
  using y = int; 
};

template <typename T, std::void_t<typename T::x>* = nullptr>
void func() {}
template <typename T, std::void_t<typename T::y>* = nullptr>
void func() {}

/*template <typename T, std::enable_if_t<std::is_same_v<typename T::x, typename T::x>>* = nullptr>
void func() {}
template <typename T, std::enable_if_t<std::is_same_v<typename T::y, typename T::y>>* = nullptr>
void func() {} */



int main() {
  func<One>();
  func<Two>();
}

Прокомментированный код работает, но первый не . Компилятор дает мне ошибки, говорящие о том, что существует переопределение и этот вывод аргумента шаблона не удался. Может ли кто-нибудь объяснить, почему это происходит? Два void_t s должны быть независимыми? Поскольку одна строка проверяет x и другую для y . Как я могу исправить?

    
задан Ekaba Bisong 30.06.2017 в 13:57
источник
  • Обратите внимание, что это работает с трюком make_void. –  Vittorio Romeo 30.06.2017 в 14:12

1 ответ

13

Это похоже на CWG-выпуск № 1980 < em> (кредиты TC для исправления меня) .

В качестве обходного пути вы можете определить void_t как:

template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;

(из cppreference)

живой пример в wandbox

    
ответ дан Vittorio Romeo 30.06.2017 в 14:14
  • Неужели эта проблема еще не исправлена ​​в новых установках C ++ 17 на gcc? –  Jun 30 '17 at 12:16 30.06.2017 в 14:16
  • std :: void_t указан как шаблон <класс ...> с использованием void_t = void; –  cpplearner 30.06.2017 в 14:45
  • Это не 1558. Это связано с совпадением объявлений, то есть, действительно ли два определения func объявляют отдельные шаблоны функций или одни и те же. Ближе к 2037 году. –  T.C. 30.06.2017 в 18:11
  • «все намеки, казалось, указывали на 1558»? Не для меня. Во-первых, вы не получаете ничего подобного «неоднозначной перегрузке», что было бы свидетельством того, что SFINAE не пинает; вместо этого вы получаете «переопределение». Во-вторых, если вы удалите одну из двух функций, то оставшаяся будет вызвана - или даст ошибку - соответственно. Это также не соответствует проблеме SFINAE. Наконец, для определения ошибки достаточно иметь только два определения функции func, без какого-либо вызова. Еще раз, это не соответствует проблеме SFINAE. –  T.C. 30.06.2017 в 20:36
  • На самом деле, CWG 1980 - это проблема точно. –  T.C. 30.06.2017 в 20:40
Показать остальные комментарии