Как работает std:: enable_if?
Я просто задал этот вопрос: std:: numeric_limits как условие
Я понимаю, где std::enable_if
будет определять возвращаемый тип метода, условно вызывающий компиляцию метода.
template<typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer, void>::type foo(const T &bar) { isInt(bar); }
То, что я не понимаю, является вторым аргументом и кажущимся бессмысленным присваиванием std::enable_if
, когда он объявлен как часть инструкции шаблона, как в Rapptz answer.
template<typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
void foo(const T& bar) { isInt(); }
Ответы
Ответ 1
Как упоминается в комментарии 40two, понимание Ошибка замещения не является Ошибка является предпосылкой для понимания std::enable_if
.
std::enable_if
- это специализированный шаблон, определяемый как:
template<bool Cond, class T = void> struct enable_if {};
template<class T> struct enable_if<true, T> { typedef T type; };
Ключевым моментом здесь является то, что typedef T type
определяется только тогда, когда bool Cond
есть true
.
Теперь, вооружившись этим пониманием std::enable_if
, ясно, что void foo(const T &bar) { isInt(bar); }
определяется:
template<typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer, void>::type foo(const T &bar) { isInt(bar); }
Как упоминалось firda, = 0
является дефолтом второго параметра шаблона. Причина по умолчанию в template<typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
заключается в том, что обе опции можно вызвать с помощью foo< int >( 1 );
. Если параметр шаблона std::enable_if
не был установлен по умолчанию, для вызова foo
потребуется два параметра шаблона, а не только int
.
В качестве примечания для пользователей версий Visual Studio до 2013 года вы не сможете использовать параметры шаблона по умолчанию, поэтому вы сможете использовать только первое определение: std:: numeric_limits как условие
Ответ 2
template<typename T, std::enable_if<std::is_integral<T>::value, int>::type = 0>
void foo(const T& bar) { isInt(); }
это не скомпилируется, если T
не является интегральным (поскольку enable_if<...>::type
не будет определено). Это защита функции foo
. Назначение = 0
есть для параметра шаблона по умолчанию, чтобы скрыть его.
Другая возможность: (да typename
отсутствует в исходном вопросе)
#include <type_traits>
template<typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
void foo(const T& bar) {}
template<typename T>
typename std::enable_if<std::is_integral<T>::value>::type
bar(const T& foo) {}
int main() {
foo(1); bar(1);
foo("bad"); bar("bad");
}
error: no matching function for call to ‘foo(const char [4])’
foo("bad"); bar("bad");
^
note: candidate is:
note: template::value, int>::type > void foo(const T&)
void foo(const T& bar) {}
^
note: template argument deduction/substitution failed:
error: no type named ‘type’ in ‘struct std::enable_if’
template::value, int>::type = 0>
^
note: invalid template non-type parameter
error: no matching function for call to ‘bar(const char [4])’
foo("bad"); bar("bad");
^