2

Consinder the following example:

#include <iostream>
#include <string>

struct foo { std::string value; };
inline foo bar() { return { "42" }; }

std::string my_func() {
    auto &x = bar();
    ^^^^^^^^^^^^^^^^
    return x.value;
}

int main() {
  std::cout << my_func() << std::endl;  
}

Compiling it both GCC and CLANG emit, most probably rightfully, the same error:

error: invalid initialization of non-const reference of type 'foo&' from an rvalue of type 'foo'

However, to my surprise it compiles and runs fine in VC++2015.

  • Is this a bug of VC++2015?
  • Does the standard dictates that auto can add implicitly constness to an object when a statement renders the program ill-formed?
101010
  • 41,839
  • 11
  • 94
  • 168

3 Answers3

3

Is this a bug of VC++2015?

The standard allows implementations to accept code that is ill-formed as extensions. However implementations are still required to issue a diagnostic (which can just mean "emit a warning when certain flags are turned on").

Does the standard dictates that auto can add implicitly constness to an object when a statement renders the program ill-formed?

No, the standard requires auto deduction to use the same rules as template argument deduction (with an exception for initializer lists). If T& will not accept it, then auto& will not.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
2

No, auto cannot add constness. However, MSVC++ has always had an extension that non-const lvalue references can bind to rvalues.

You can disable this extension with the /Za switch, I think.

M.M
  • 138,810
  • 21
  • 208
  • 365
1

Is this a bug of VC++2015?

Redmond-defendants often call it a "feature", but it is a completely stupid bug in that mess of a compiler (fixable with /Za). Let's see why...

auto &x = bar();

Okay, so you are calling bar(), no? This produces an rvalue, that is, an object without an address. Now, you can't bind an lvalue (an object whose address can be obtained) reference (a.k.a: &) to an rvalue. So far, that's the reason your code is illegal.

However, there's a special rule in the C++ language that allows a const lvalue reference to bind to an rvalue, effectively extending its lifetime. So, this would be valid code...

const auto &x = foo();

Edit: BTW...

Does the standard dictates that auto can add implicitly constness to an object when a statement renders the program ill-formed?

To put it in non-standardese terminology/plain English, if T& is rejected, so will auto&. CV-qualifiers (const and volatile) are not automatically deduced from auto.

I hope this has led some light on you!

3442
  • 8,248
  • 2
  • 19
  • 41
  • "CV-qualifiers (`const` and `volatile`) are not automatically deduced from `auto`." Not quite. `const int c = 1; auto& d = c; /* OK, d is const int & */` It doesn't conjure cv-qualifiers out of thin air, but if the initializer is cv-qualified it's perfectly happy to deduce it – T.C. Nov 06 '15 at 02:06
  • To @T.C. I would add that it even works with an rvalue: `auto& d = std::move(c)` will compile. But you don't see const-qualified rvalues that much. – Brian Bi Nov 06 '15 at 02:32
  • What are you on about? I currently work with GNU/Linux and privately have a Mac, and yet I *have* to defend "Redmond" because compilers are free to accept ill-formed code as extensions (except a warning may be required, as has been mentioned). Whether this particular extension is worthwhile is a different topic. For example, the GCC developers in fact have been as happy to provide extensions as any other compiler team – remember C++ signatures? There's no "pure standard C++" compiler I know of, not even only by default. – Arne Vogel Nov 06 '15 at 10:25
  • @ArneVogel: GNU/Linux, of course ;). My point is that most of those "features" where reported as bugs long before being claimed as features, not to mention the fact they're barely documented. GCC at least documents `__attribute__(())`... – 3442 Nov 06 '15 at 10:28