Für std::string
wird die primäre Vorlage ausgewählt und die Spezialisierung berücksichtigt. Aber decltype(++std::declval<T&>())
ist schlecht gebildet, so dass es nicht berücksichtigt wird und die primäre Vorlage (nicht spezialisierte Vorlage) verwendet wird, die 0
ergibt.
Wenn Sie int
verwenden, wird es ein bisschen komplizierter. Die primäre Vorlage wird wie immer vom Compiler ausgewählt, und dann wird die Spezialisierung berücksichtigt (weil Spezialisierung immer als bessere Übereinstimmung betrachtet wird). Die Spezialisierung ist <int, int&>
für int
, aber es stimmt nicht mit der nicht spezialisierten Vorlage <int, void>
überein (das void
ist das Standardschablonenargument), daher wird die Spezialisierung ignoriert, da sie nicht übereinstimmt.
Also müssen die Typen des Standard-Template-Parameters übereinstimmen, sonst wird die Spezialisierung nicht berücksichtigt, da eine Spezialisierung nur dann erfolgt, wenn jedes Template-Argument der Spezialisierung entspricht.
hängen Sie einfach ein void()
am Ende die Spezialisierung Spiel für die zweiten Template-Parameter zu machen, wie die linken verworfen und die Art der void()
ist void
, die die primäre Vorlage der zweiten Template-Parameter übereinstimmt.
template<typename T>
struct is_incrementable<T, decltype(++std::declval<T&>(), void())> : std::true_type {};
In C++ 17, würden Sie std::void_t
dafür.
Dies ist der Ort für [std :: void_t] (http://ideone.com/QUJxId). – DeiDei
Darüber hinaus haben die Dokumente für void_t genau diese Art von Code als Beispiel, siehe http://en.cppreference.com/w/cpp/types/void_t Code für 'has_pre_increment_member' – stijn