ref qualifier gives error in gcc4.7.2 and vc10 - c++

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.

Related

Invoking `constexpr` member function through reference - clang vs gcc

Consider the following example (snippet (0)):
struct X
{
constexpr int get() const { return 0; }
};
void foo(const X& x)
{
constexpr int i = x.get();
}
int main()
{
foo(X{});
}
The above example compiles with all versions of g++ prior to g++ 10.x, and never compiled under clang++. The error message is:
error: 'x' is not a constant expression
8 | constexpr int i = x.get();
|
live example on godbolt.org
The error kind of makes sense, as x is never a constant expression in the body of foo, however:
X::get() is marked constexpr and it does not depend on the state of x;
Changing const X& to const X makes the code compile with every compiler (on godbolt.org) snippet (1).
It gets even more interesting when I mark X::get() as static ((on godbolt.org) snippet (2)). With that change, all tested versions of g++ (including trunk) compile, while clang++ still always fail to compile.
So, my questions:
Is g++ 9.x correct in accepting snippet (0)?
Are all compilers correct in accepting snippet (1)? If so, why is the reference significant?
Are g++ 9.x and g++ trunk correct in accepting snippet (2)?
Is g++ 9.x correct in accepting snippet (0)?
No.
Are all compilers correct in accepting snippet (1)? If so, why is the reference significant?
Yes, they are.
A constant expression cannot use an id-expression naming a reference that doesn't have a previous constant expression initialization or began its lifetime during the constant expression evaluation. [expr.const]/2.11 (same in C++20)
The same is not true if you are naming a non-reference variable without involving any lvalue-to-rvalue conversion. x.get() only refers to x as lvalue and only calls a constexpr function that doesn't actually access any member of x, so there is no issue.
Are g++ 9.x and g++ trunk correct in accepting snippet (2)?
No, because the expression still contains the subexpression x which violates the rule mentioned above.

Why VS fails to bind rvalue reference to a pointer?

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

Using a this pointer in a generic lambda capture

I have an issue in which Clang (3.6) and G++ (5.1) have a differing opinion:
#include <functional>
struct X
{
X()
{
std::function<void (int)> f = [this](auto x){foo(x);};
}
void foo(int x){}
};
int main(){}
Clang accepts this, whereas G++ states:
error: cannot call member function ‘void X::foo(int)’ without object
Both compilers accept it if I call this->foo(x) directly instead, but I'd rather know who's right.
Note: both the "auto" in the lambda signature and the conversion to a std::function<> are required to trigger this case.
Both compilers accept it if I call this->foo(x) directly instead, but I'd rather know who's right.
Considering it compiles in gcc 5.2, clang is the one correct in your specific case. It looks like it was just a bug in gcc 5.1. gcc 6.0 also compiles this fine.
Plus it makes intuitive sense, this should be implied.

Compile error: boost::promise<T>::set_value(const T&) doesn't exist

I'm having problems with Boost.Thread's futures: I can't seem to put anything but a primitive type into a promise, future, or packaged task.
Here is a minimal testcase:
#include <boost/thread/future.hpp>
struct foo
{
foo(int i_): i(i_) {}
int i;
};
int main()
{
// A const future isn't much use, but I needed to prove
// the problem wasn't me trying to copy a unique_future
const boost::unique_future<foo>& fut = boost::make_ready_future( foo(42) );
}
With BOOST_THREAD_USES_MOVE defined before including the Boost.Future header I get the following error with gcc 4.8.2 and Boost 1.55 (full output here):
../../deps/boost/include/boost/thread/future.hpp:3634:5: error: no matching function for call to ‘boost::promise<foo>::set_value(const foo&)’
p.set_value(boost::forward<future_value_type>(value));
^
There seems to be no overload of promise::set_value() that takes a const lvalue reference. Looking at promise and future_traits in future.hpp it seems that the const lvalue ref overload will only exist when BOOST_NO_CXX11_RVALUE_REFERENCES is undefined. That makes no sense to me however...surely the const lvalue ref overload is needed precisely when there are no rvalue references? (Note this happens even if I pass a mutable lvalue ref to make_ready_future()).
If I don't define BOOST_THREAD_USES_MOVE it fails compilation with the following error (full output here):
../../deps/boost/include/boost/thread/detail/move.hpp:183:54: error: no matching function for call to boost::unique_future<foo>::unique_future(boost::unique_future<foo>)’
#define BOOST_THREAD_MAKE_RV_REF(RVALUE) RVALUE.move()
^
Have I missed something?
It seems from the boost-users mailing list that this is a bug in Boost and is also present in 1.56 - looks like it's fundamentally broken in C++03 mode.
Bug report: https://svn.boost.org/trac/boost/ticket/10340

Can temporaries bind to non-const references?

I wrote the following code to test this:
struct X
{
char* x;
X()
{
x = new char('a');
}
~X()
{
*x = 'b';
delete x;
}
};
void foo(const X& x)
{
}
void goo(X& x)
{
}
int main()
{
foo(X());
goo(X());
}
The destructors for the temporaries are called after both functions exit, but I thought you can only bind a temporary to a const reference. Why does goo work then?
Is it UB and MSVS is wrong, or is it ok?
It's illegal. A conforming implementation diagnoses it (i.e. it must at least warn), but MSVC++ allows it as an extension.
Or a bug if you're unkind, but IIRC the reason they still allow it is for long-lived legacy reasons: nominally to support code written for MSVC++ before C++ was standardized, but of course once you allow people to write this, they write it accidentally in new code too, so the legacy lives on. If it's deliberate then it's a (mis-)feature, not a bug, right? Anyway, a conforming implementation is required to diagnose ill-formed programs, so if you don't get a warning then the compiler isn't conforming.
This is apparently a MS extension. In GCC 4.3.4, for instance, it fails to compile, with the following message:
prog.cpp: In function ‘int main()’:
prog.cpp:25: error: invalid initialization of non-const reference of type ‘X&’ from a temporary of type ‘X’
prog.cpp:18: error: in passing argument 1 of ‘void goo(X&)’