views:

147

answers:

1

Edit:

This is indeed a bug in the compiler, I've opened a defect and got the following response.

Hello Motti,
Thank you for submitting this issue. As noted in the stackoverflow posting, this is a bug in our decltype implementation. Unfortunately, we cannot fix this bug in the next release of Visual Studio since the code is relatively uncommon, and we are particularly resource constrained.

Original question follows


I'm playing around with the C++0x features of VS10 and I ran into the following problem.

std::map<int, int> map()
{
    return std::map<int, int>();
}

template <class F>
auto call(F f) -> decltype(f())
{       
    auto ret = f();
    return ret;
}

void check() 
{
    auto m = call(map); 
}

I get the following warning:

warning C4172: returning address of local variable or temporary

However when I change the prototype of call to be the old style:

std::map<int, int> call(F f)

It's fine, it's also OK when call is not a template function (even when using deduced return types).

If I look at the type of ret it's std::map<int, int> (no references or pointers).

Is this a bug in VS10 or am I missing something.

+3  A: 

call(map); implicitly converts map to a function pointer, to make the function:

auto call( std::map<int,int>(*f)() ) -> decltype(f())

It looks like VC10 isn't meeting the c++0x FCD for decltype, which says:

The type denoted by decltype(e) is defined as follows:

  • if e is an unparenthesized id-expression or a class member access [snip, it isn't]

  • otherwise, if e is a function call (5.2.2) or [snip], decltype(e) is the return type of the statically chosen function;

  • otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e;

  • otherwise, decltype(e) is the type of e.

5.2.2 makes it clear that calling through a function pointer is a "function call" so decltype(f()) should be std::map<int,int>. Instead, it's treating f() like an lvalue espression, with the result std::map<int,int> &. The type of ret is being inferred correctly, but it's being cast into a reference by the return.

This bug doesn't show up when you use a function expression instead of a function pointer expression, decltype(map()) correctly results in std::map<int,int>.

BCoates