Why VS fails to bind rvalue reference to a pointer? - c++

Consider the following example (for hypothetical purposes):
#include <iostream>
void f(int *&&b)
{
++b;
std::cout << *b;
}
int main()
{
int a[] = { 1,2,3,4 };
f(a);
}
To my humble understanding, the array a decays into an int *, which is temporary and thus an rvalue, and int *&&b should happily bind to it and extend its life for the scope of the function f. And this is what happens if I run this with C++14 (gcc 6.3) and the result is 2. In VS2017 however, I get an error:
Error C2664 'void f(int *&&)': cannot convert argument 1 from 'int
[4]' to 'int *&&'
If I use std::move to force xvalue f(std::move(a)); it also works in VS. Do I need to use std::move in this case or is this a some sort of bug in VS?

Your program looks well formed and it is accepted by GCC and Clang.
It appears to be a bug in Visual Studio compiler, which manifested itself till compiler version 19.28 and was finally fixed in compiler version 19.29. Demo:
https://gcc.godbolt.org/z/KbhGfhPbG

Related

auto reference to Eigen object not compiling with GCC, but compiling with MSVC [duplicate]

Why does this compile on MS Visual C++?
struct myClass{};
void func(myClass& arg){}
void main() {
func( myClass() ); // works even though func only takes myClass&
} // (not const myClass&!!)
Does this work on other compilers as well or is this MSVC specific (or even a compiler bug?). I can even get the reference on this rvalue like this:
void func(myClass* arg){}
int main() {
func( &myClass() );
}
This works ONLY on Objects that are temporarily created with a constructor. This wouldn't work with any other rvalue like (myClass() + myClass()) for example..
It compiles because MSVC has a non-standard compliant "extension" that allows binding non-const references to temporaries.
The first example should not compile on a standards compliant compiler.
In the second example, you are taking the address of a temporary to set the value of a pointer. This should also result in an error.
Clang 3.2 produces:
error: taking the address of a temporary object of type 'Foo' [-Waddress-of-temporary]
while GCC 4.7.3 produces
error: taking address of temporary [-fpermissive]
MSVC 2017 with default project settings (that now include /permissive- flag) yields an error:
error C2664: 'void func(myClass &)': cannot convert argument 1 from 'myClass' to 'myClass &'
note: A non-const reference may only be bound to an lvalue
Even if /permissive- option is not viable for some reason using /W4 will yield a warning:
warning C4239: nonstandard extension used: 'argument': conversion from 'myClass' to 'myClass &'
note: A non-const reference may only be bound to an lvalue

GCC allows arrays to be returned from function - bug or feature?

I was amazed to find out that GCC allows functions to return arrays when trailing return type is used instead of normal one. As you probably knows arrays can't be copied so this is quite limited but let me show you some cool example.
#include <iostream>
#include <typeinfo>
using namespace std;
auto func() -> int [5]
{
return {4, 56, 78, 4, 0};
}
int main()
{
cout << func()[2] << endl;
cout << typeid(func).name() << endl;
}
Is this a compiler bug or some new feature?
Interestingly 'typeid' returns 'FA5_ivE' which is demangled as 'int (()) [5]' and this means exactly what you think an function returning array of 5 int's.
EDIT: I tried bounding the returned array into rvalue reference but without any success (used most of the possible forms):
auto &&refArrayTemp{ func() };
Seems that this extensions is rather useless.
This was a bug in gcc (fixed as of 2017-07-03), caused by inconsistent treatment of trailing-return-types.
First note the difference in error message between two attempts to declare a function returning a function:
using Fv = void();
Fv f1(); // error: 'f1' declared as function returning a function
auto f2() -> Fv; // error: function return type cannot be function
The first error comes from decl.c, handling declarators, while the second is a lot deeper into the internals, from tree.c, attempting to build the function type preparatory to generating code.
Trailing-return-types are handled in decl.c 30 lines below the above error - too late to catch it with the above error code, and it is not handled separately.
With arrays, similarly using a trailing-return-type allows us to skip the checks in decl.c, the difference being that function-returning-array is actually valid in terms of gcc's internal representation.
Note that you can't do much with it; gcc doesn't allow you to assign, reference-bind, decay or pass the result of func() to another function:
auto a1 = func();
// error: invalid use of non-lvalue array
auto& a2 = func();
// error: invalid initialization of non-const reference of type 'int (&)[5]' from an rvalue of type 'int [5]'
auto&& a3 = func();
// error: lvalue required as unary '&' operand
Indeed, even your code is rejected at -Wpedantic:
warning: ISO C++ forbids subscripting non-lvalue array
Finally, by exploiting a similar bug (qualifiers are stripped from scalars before handling of trailing-return-types) we can create a function with type int const volatile():
int const volatile g1(); // warning: type qualifiers ignored on function return type
auto g2() -> int const volatile; // OK!!
Latest draft, [dcl.array]/p10:
Functions shall not have a return type of type array or function, although they may have a return type of
type pointer or reference to such things. There shall be no arrays of functions, although there can be arrays
of pointers to functions.
This could be a non-standard GCC extension. It doesn't compile in the trunk version of clang. However, this may also be a bug since it has inconsistent behavior with a non-trailing return type.

Does C++11 require this lambda to be declared mutable?

Consider this C++11 code:
#include <functional>
#include <cstdlib>
template <typename F>
void test(F &&f) {
auto foo = [f]() {
f();
};
foo();
}
int main() {
test(std::bind(std::puts, "hello"));
return 0;
}
GCC and Clang accept this as valid C++11 code, but Visual Studio 2013 requires the lambda to be declared mutable (auto foo = [f]() mutable { ... }). Otherwise I get this error:
error C3848: expression having type 'const std::_Bind<true,int,int (__cdecl *const )(const char *),const char (&)[6]>' would lose some const-volatile qualifiers in order to call 'int std::_Bind<true,int,int (__cdecl *const )(const char *),const char (&)[6]>::operator ()<>(void)'
Is Visual Studio right to reject this code without mutable, or is it valid C++11?
(Curiously Clang rejects the code if you change std::bind(std::puts, "hello") to std::bind(std::exit, 0) apparently because it considers noreturn to make the function type different; I'm quite sure this is a bug.)
This isn't really about lambdas.
#include <functional>
#include <cstdlib>
int main() {
const auto x = std::bind(std::puts, "hello");
x();
}
This is accepted by GCC, but rejected by MSVC.
The standard is unclear on whether this is valid, IMO. The return value g of std::bind has an unspecified return type for which g(...) is valid and defined in terms of the cv-qualifiers of g, but the standard doesn't actually say that any operator() must be callable for const-qualified objects or references. It strongly implies that this is intended to be valid, because otherwise the reference to g's cv-qualifiers seems useless, but it doesn't actually say it is valid.
Because of that, I think MSVC's behaviour is not what the standard's authors intended, but it may nonetheless conform to what the standard requires.
This looks like a bug in the Visual Studio implementation of bind, returning a type with only a non-const function call operator. It should return a type that forwards all function calls to the bound function object, regardless of its own cv-qualifications.
To summarise the rather opaque language of C++11 20.8.9.1.2, function calls on the result of bind should be forwarded to the bound function object, and so should be allowed if calls on that object would be allowed. So it would be an error if the bound function object weren't callable if const; but here, being a function pointer, it is callable regardless of cv-qualifications.

Inconsistent overload resolution with rvalue references

My understanding of overload resolution is that 'T&&' is generally a better match than 'const T&'. However, I'm seeing some inconsistent behavior among compilers with this trivial example:
#include <iostream>
void Func(const double& a)
{
(void)a;
std::cout << "[lvalue]\n";
}
void Func(double&& a)
{
(void)a;
std::cout << "[rvalue]\n";
}
template <typename T>
void TFunc(T&& a)
{
Func(a);
}
int main ()
{
TFunc(5.5f);
return 0;
}
Clang 3.2 will print [rvalue]. However, the VS2013 32bit/64bit compilers will print [lvalue]. If I change '5.5f' to '5.5', then both compilers will print [lvalue].
I can understand why the VS compiler chooses the 'const double&' version since I don't have a std::forward call to preserve the '&&' of the parameter. However, I still don't understand what makes clang think that the '&&' overload is the better choice.
Why does adding an implicit float to double conversion affect the behavior in clang? Who is right?
When you call with 5.5f, T is float, and the Func call effectively becomes Func(double(a)). The argument is a temporary, and so rvalue overload should be chosen.
When you call with 5.5, T is double, and no temporary is created in a call to Func(a). A named variable cannot bind to an rvalue reference, so lvalue overload is the only choice.
MSVC has a long-standing misfeature that allows temporaries to bind to non-const lvalue references. This is why it incorrectly chooses lvalue overload even in the first case. Try compiling with /Za (disable language extensions) - I believe it would match clang's behavior then.

ref qualifier gives error in gcc4.7.2 and vc10

consider the below minimal example.
#include<iostream>
struct A
{
A(){std::cout<<"def"<<'\n';}
void foo()&{std::cout<<"called on lvalue"<<'\n';}
};
int main()
{
A a;
a.foo();
A().foo();
return 0;
}
this gives error about expecting ';' at the end of declaration and and expected un-qualified-id before '{'.
Can i know what i'm doing wrong? in the actual code i want to avoid calling the non-static member function through temporaries.
tried on gcc 4.7.2 and vc2010.
Thanks.
The answer will be short: VC10 and GCC 4.7.2 do not support ref-qualifiers.
However, notice that your foo() function has an lvalue ref qualifier, meaning that you cannot invoke it on temporaries.
If you want this expression to compile as well:
A().foo();
Then you should use const&, or provide an overload for &&, as in this live example.
To work with ref-qualifiers you can use Clang 3.2 or GCC 4.8.1.