"Emulating" std::declval issues. Works (kind of) in g++, fails to compile in clang++

228 views Asked by At

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):

  1. Is the code above legal? Is my usage of decltype(Barref.f()) really the same as using decltype(std::declval<Bar>().f())? It seems a bit weird, as Barref.f() is not really a return value of a function (even if un-evaluated). I realized that even decltype(Bar.f()) compiles (g++), with no type alias whatsoever.

  2. If the code is legal, why does the type of x is int instead of double?

1

There are 1 answers

3
T.C. On BEST ANSWER

Minimized to

struct Meow {};

int main(){
    decltype(Meow.purr()) d;
}

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

struct Meow {};
decltype(Meow.purr()) d;