Trying to better understand std::declval, I came up with the following "toy model" code:
#include <iostream>
#include <typeinfo>
struct Bar
{
Bar(double); // some non-default ctor
double f(); // some function of which return type we want to get
};
using Barref = Bar&&; // emulating std::declval<Bar>()
int main()
{
// FUNKY, compiles in g++, not in clang++
// error: unexpected type name 'Barref': expected expression
decltype(Barref.f()) x; // (1)
std::cout << typeid(x).name() << std::endl; // i -> int INCORRECT
// OK, just for testing
decltype(std::declval<Bar>().f()) y; // (2)
std::cout << typeid(y).name() << std::endl; // d -> double CORRECT
}
So I'm typedef-ing Barref as a rvalue reference of type Bar&&, and use it in an a decltype expression in (1). If I understand correctly, this is exactly what std::declval does, it is a non-defined function that returns a rvalue reference to its template parameter
template<class T>
typename std::add_rvalue_reference<T>::type declval();
so we can then use the latter in unevaluated contexts, such as decltype. It is useful whenever the type has a non-default ctor, and we'd like to get some type information about some member function without the need to construct the object. Well, that's what I though my code below does. g++5.1 compiles it, but x is of type int (instead of double, as I would have guessed). However, clang++ fails to compile the code, saying
error: unexpected type name 'Barref': expected expression decltype(Barref.f()) x;
My question(s):
Is the code above legal? Is my usage of
decltype(Barref.f())really the same as usingdecltype(std::declval<Bar>().f())? It seems a bit weird, asBarref.f()is not really a return value of a function (even if un-evaluated). I realized that evendecltype(Bar.f())compiles (g++), with no type alias whatsoever.If the code is legal, why does the type of
xisintinstead ofdouble?
Minimized to
This is plainly invalid code, yet GCC 5.1 and trunk accept it. Not much to say about it other than "bug". Interestingly, both correctly rejects