Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is decltype with two arguments?

Edit, in order to avoid confusion: decltype does not accept two arguments. See answers.

The following two structs can be used to check for the existance of a member function on a type T during compile-time:

// Non-templated helper struct: struct _test_has_foo {     template<class T>     static auto test(T* p) -> decltype(p->foo(), std::true_type());      template<class>     static auto test(...) -> std::false_type; };  // Templated actual struct: template<class T> struct has_foo : decltype(_test_has_foo::test<T>(0)) {}; 

I think the idea is to use SFINAE when checking for the existance of a member function, so in case p->foo() isn't valid, only the ellipses version of test, which returns the std::false_type is defined. Otherwise the first method is defined for T* and will return std::true_type. The actual "switch" happens in the second class, which inherits from the type returned by test. This seems clever and "lightweight" compared to different approaches with is_same and stuff like that.

The decltype with two arguments first looked surprising to me, as I thought it just gets the type of an expression. When I saw the code above, I thought it's something like "try to compile the expressions and always return the type of the second. Fail if the expressions fail to compile" (so hide this specialization; SFINAE).

But:

Then I thought I could use this method to write any "is valid expression" checker, as long as it depends on some type T. Example:

...     template<class T>     static auto test(T* p) -> decltype(bar(*p), std::true_type()); ... 

http://ideone.com/dJkLPF

This, so I thought, will return a std::true_type if and only if bar is defined accepting a T as the first parameter (or if T is convertible, etc...), i.e.: if bar(*p) would compile if it was written in some context where p is defined of type T*.

However, the modification above evaluates always to std::false_type. Why is this? I don't want to fix it with some complicated different code. I just want to know why it doesn't work as I expected it to. Clearly, decltype with two arguments works different than I thought. I couldn't find any documentation; it's only explained with one expression everywhere.

like image 418
leemes Avatar asked Apr 16 '13 18:04

leemes


People also ask

What is the decltype of a function?

If the expression parameter is a call to a function or an overloaded operator function, decltype(expression) is the return type of the function. Parentheses around an overloaded operator are ignored. If the expression parameter is an rvalue, decltype(expression) is the type of expression.

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 )

Does decltype evaluate expression?

The following expressions do not evaluate their operands: sizeof() , typeid() , noexcept() , decltype() , and declval() . Because an unevaluated operand in an expression is not evaluated, no side effects from that operand are triggered. Reliance on those side effects will result in unexpected behavior.

What does decltype return?

decltype returnsIf 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.


1 Answers

It's an comma-separated list of expressions, the type is identical to the type of the last expression in the list. It's usually used to verify that the first expression is valid (compilable, think SFINAE), the second is used to specify that decltype should return in case the first expression is valid.

like image 101
Daniel Frey Avatar answered Sep 27 '22 17:09

Daniel Frey