Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange operator ?: usage with decltype

Tags:

c++

decltype

I am reading a book, that explains C++ traits and there is an example from C++ type_traits header with a strange ?: usage, here is the quote from the corresponding /usr/include/c++/... file:

template<typename _Tp, typename _Up>
  static __success_type<typename decay<decltype
                        (true ? std::declval<_Tp>()
                         : std::declval<_Up>())>::type> _S_test(int);

Setting aside the purpose of the given declaration, the ?: operator usage puzzles me in this code. If the first operand is true, then std::declval<_Tp>() will always be chosen as result of the evaluation. How does that declval operand selection actually works?

Edit: originally read in Nicolai M. Josuttis's "The C++ Standard Library: A Tutorial and Reference, 2nd ed.", p.125. But there it is given in a slightly simplified form as compared to what my GCC header files has.

like image 441
Student4K Avatar asked Oct 02 '16 09:10

Student4K


People also ask

What is decltype used for?

The decltype type specifier, together with the auto keyword, is useful primarily to developers who write template libraries. Use auto and decltype to declare a template function whose return type depends on the types of its template arguments.

What does decltype stand for?

Decltype keyword in C++ Decltype stands for declared type of an entity or the type of an expression. It lets you extract the type from the variable so decltype is sort of an operator that evaluates the type of passed expression. SYNTAX : decltype( expression )

What does decltype return?

decltype returns If what we pass to decltype is the name of a variable (e.g. decltype(x) above) or function or denotes a member of an object ( decltype x.i ), then the result is the type of whatever this refers to. As the example of decltype(y) above shows, this includes reference, const and volatile specifiers.


2 Answers

In the expression true ? std::declval<_Tp>() : std::declval<_Up>() the first alternative is always selected, but the whole expression must be a valid expression. So std::declval<_Up>() must be valid and that means _Up must be a callable that accepts zero arguments. Beside that, _Tp() and _Up() must return the same type (or one of the types must be implicitly convertible to another), otherwise ternary iterator would not be able to select return value.

This technique is called SFINAE (substitution failure is not an error). The idea is that if template instantiation fails, then it is not an error, and this template is just ignored and compiler searches for another one.

like image 187
Alexey Guseynov Avatar answered Sep 29 '22 20:09

Alexey Guseynov


The idea here is that ?: requires that the second and third operand has the same type, or one type is convertible to the other.

Otherwise the instantiation of the function will fail, and some other overload is selected.

like image 22
Bo Persson Avatar answered Sep 29 '22 19:09

Bo Persson