The 2nd edition of C++ Templates - The Complete Guide features the following footnote at page 436 (my bold):
Except that
decltype(call-expression)does not require a nonreference, non-voidreturn type to be complete, unlike call expressions in other contexts. Usingdecltype(std::declval<T>().begin(), 0)instead does add the requirement that the return type of the call is complete, because the returned value is no longer the result of thedecltypeoperand.
The footnote refers to the fact that decltype(std::declval<T>().begin()) is used (ineffectively, based on the footnote) to test whether it is valid to call .begin() on a T. The code that uses it is the following (with some pieces of text around it for clarity:
the trick is to formulate the expression that checks whether we can call
begin()inside adecltypeexpression for the default value of an additional function template parameter:#include <utility> // for declval #include <type_traits> // for true_type, false_type, and void_t // primary template: template<typename, typename = std::void_t<>> struct HasBeginT : std::false_type {}; // partial specialization (may be SFINAE’d away): template<typename T> struct HasBeginT<T, std::void_t<decltype(std::declval<T>().begin())>> : std::true_type { };Here, we use
decltype(std::declval<T>().begin())to test whether, given a value/object of typeT(usingstd::declvalto avoid any constructor being required), calling a memberbegin()is valid.
From this previous question of mine, I've understood that since operator, can be overloaded, the role of the , 0 is to trigger the otherwise absent overload resolution, which in turn needs the type of std::declval<T>().begin() to be complete.
However, the text from the book (see the part highlighted in bold above), doesn't mention operator,, nor overload resolution. Is that just bad wording? Or maybe it's just the same matter looked from a different perspective? Or what?