Ответ 1
Для std::string
выбирается первичный шаблон и рассматривается специализация. Но decltype(++std::declval<T&>())
плохо сформирован, поэтому он не рассматривается и используется первичный шаблон (неспециализированный шаблон), что приводит к 0
.
Если вы используете int
, это становится немного сложнее. Основной шаблон выбирается компилятором, как всегда, и затем рассматривается специализация (потому что специализация всегда считается лучшим совпадением). Специализация <int, int&>
для int
, но она не соответствует неспециализированному шаблону <int, void>
(void
является аргументом шаблона по умолчанию), поэтому специализация игнорируется, потому что она не соответствует.
Таким образом, типы параметров шаблона по умолчанию должны совпадать, или специализация не учитывается, так как специализация выполняется только тогда, когда каждый аргумент шаблона соответствует специализации.
Просто добавьте void()
в конец, чтобы сделать совпадение специализации для второго параметра шаблона, поскольку левое выражение отбрасывается, а тип void()
- void
, который соответствует параметру второго шаблона основного шаблона.
template<typename T>
struct is_incrementable<T, decltype( ++std::declval<T&>(), void() )> : std::true_type {};
В С++ 17 вы используете std::void_t
для этого.