[contract] auto_..._error regression tests fail on C++1z
Hello all, I asked this question on compl.c++ list as well, given this is more of a general C++1z question than a Boost question. However, this is making some Boost.Contract regression tests fail on C++1z compilers so I wanted to ask it here as well hoping to get some info more quickly... Following code prevents copies outside its friend function f: // File: 05.cpp struct x { x() {} private: x(x const&) {} x& operator=(x const&) { return *this; } friend x f(); }; x f() { return x(); } int main() { auto xx = f(); return 0; } Correctly it does not compile up to C++1y because main cannot access the copy operations: $ clang++ -std=c++1y 05.cpp 05.cpp:14:15: error: calling a private constructor of class 'x' auto xx = f(); ^ 05.cpp:5:5: note: declared private here x(x const&) {} ^ 1 error generated. However, it compiles on C++1z?! $ clang++ -std=c++1z 05.cpp # Not compiler errors?! Why... what changed in C++1z that makes the above compile? How can I prevent copying x outside its friend function f in C++1z? Thanks, --Lorenzo
Why... what changed in C++1z that makes the above compile? How can I prevent copying x outside its friend function f in C++1z?
C++ 17 guarantees copy elision in the strong sense. Note it still can't be copied, but it can be initialised now. So disable non-friend construction to fix. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/
On Thu, Sep 28, 2017 at 4:05 PM, Niall Douglas via Boost
Why... what changed in C++1z that makes the above compile? How can I prevent copying x outside its friend function f in C++1z?
C++ 17 guarantees copy elision in the strong sense.
Note it still can't be copied, but it can be initialised now. So disable non-friend construction to fix.
I see. However, making the constructor private still does not make the compilation fail. The following code compiles fine on clang++ -std=c++1z ... struct x { private: x() {} x(x const&) {} x& operator=(x const&) { return *this; } friend x f(); }; x f() { return x(); } int main() { auto xx = f(); return 0; } Is there any way to make that `auto xx = f()` in main fail at compile time in C++1z? Thanks, --Lorenzo
2017-09-29 4:29 GMT+02:00 Lorenzo Caminiti via Boost
On Thu, Sep 28, 2017 at 4:05 PM, Niall Douglas via Boost
wrote: Why... what changed in C++1z that makes the above compile? How can I prevent copying x outside its friend function f in C++1z?
C++ 17 guarantees copy elision in the strong sense.
Note it still can't be copied, but it can be initialised now. So disable non-friend construction to fix.
I see. However, making the constructor private still does not make the compilation fail. The following code compiles fine on clang++ -std=c++1z ...
struct x { private: x() {} x(x const&) {} x& operator=(x const&) { return *this; }
friend x f(); };
x f() { return x(); }
int main() { auto xx = f(); return 0; }
Is there any way to make that `auto xx = f()` in main fail at compile time in C++1z?
But why do you want this program to fail to compile? Regards, &rzej;
On Tue, Oct 3, 2017 at 11:45 PM, Andrzej Krzemienski via Boost
2017-09-29 4:29 GMT+02:00 Lorenzo Caminiti via Boost
Is there any way to make that `auto xx = f()` in main fail at compile time in C++1z?
But why do you want this program to fail to compile?
The library requires to explicitly use `boost::contract::check c = boost::contract::function()`. Using `auto c = boost::contract::function()` or `boost::contract::function()` (without assigning it to anything) will generate a run-time error. This is well documented. On non C++1z compilers, the library will also give a compile-time error if `auto c = boost::contract::function()` is used by mistake (but this no longer fails compilation on C++1z so you are left with just the run-time error in that case on C++1z). In summary, this is just to catch a misuse of the API at compile-time instead of run-time... this is well documented so it shouldn't be a real issue in practice. P.S. I'm surprised that I can no longer write a type in C++1z that will fail compilation when used via its copy operations... I wonder if that is an unintended consequence of the zero-copy optimization guarantee that C++1z has. Sure no copies should be made at run-time, but I should still get a compile-time error if I try to use a copy operation on a type that does allow copy, even when these copies are guaranteed to be optimized away in C++11z. Thanks. --Lorenzo
On 10/4/2017 12:48 PM, Lorenzo Caminiti via Boost wrote:
On Tue, Oct 3, 2017 at 11:45 PM, Andrzej Krzemienski via Boost
wrote: 2017-09-29 4:29 GMT+02:00 Lorenzo Caminiti via Boost
Is there any way to make that `auto xx = f()` in main fail at compile time in C++1z?
But why do you want this program to fail to compile?
The library requires to explicitly use `boost::contract::check c = boost::contract::function()`. Using `auto c = boost::contract::function()` or `boost::contract::function()` (without assigning it to anything) will generate a run-time error. This is well documented. On non C++1z compilers, the library will also give a compile-time error if `auto c = boost::contract::function()` is used by mistake (but this no longer fails compilation on C++1z so you are left with just the run-time error in that case on C++1z).
In summary, this is just to catch a misuse of the API at compile-time instead of run-time... this is well documented so it shouldn't be a real issue in practice.
P.S. I'm surprised that I can no longer write a type in C++1z that will fail compilation when used via its copy operations... I wonder if that is an unintended consequence of the zero-copy optimization guarantee that C++1z has. Sure no copies should be made at run-time, but I should still get a compile-time error if I try to use a copy operation on a type that does allow copy, even when these copies are guaranteed to be optimized away in C++11z.
I think you mistyped and should have written: "but I should still get a compile-time error if I try to use a copy operation on a type that does not allow copy, even when these copies are guaranteed to be optimized away in C++11z." I agree with that sentiment also, so I am equally surprised that a compile-time error does not occur. I would be very interested in the part of the C++17 standard which explains why I do not get a compile-time error in the example case where f() is a private function.
Thanks. --Lorenzo
On Wed, 2017-10-04 at 09:48 -0700, Lorenzo Caminiti via Boost wrote:
On Tue, Oct 3, 2017 at 11:45 PM, Andrzej Krzemienski via Boost
wrote: 2017-09-29 4:29 GMT+02:00 Lorenzo Caminiti via Boost
Is there any way to make that `auto xx = f()` in main fail at compile time in C++1z?
But why do you want this program to fail to compile?
The library requires to explicitly use `boost::contract::check c = boost::contract::function()`. Using `auto c = boost::contract::function()` or `boost::contract::function()` (without assigning it to anything) will generate a run-time error. This is well documented. On non C++1z compilers, the library will also give a compile-time error if `auto c = boost::contract::function()` is used by mistake (but this no longer fails compilation on C++1z so you are left with just the run-time error in that case on C++1z).
In summary, this is just to catch a misuse of the API at compile-time instead of run-time... this is well documented so it shouldn't be a real issue in practice.
P.S. I'm surprised that I can no longer write a type in C++1z that will fail compilation when used via its copy operations... I wonder if that is an unintended consequence of the zero-copy optimization guarantee that C++1z has. Sure no copies should be made at run-time, but I should still get a compile-time error if I try to use a copy operation on a type that does allow copy, even when these copies are guaranteed to be optimized away in C++11z.
Yes, this is the semantic difference with guaranteed copy elision. So now `NonMoveable x = NonMoveable{5}` is semantically equivalent to `NonMoveable x{5}`. This is done by tweaking the value categories, so `NonMoveable{5}` no longer produces a temporary object, but rather `NonMoveable{5}`(ie a prvalue) performs initialization at the location of `NonMoveable x`(ie a glvalue). There are exceptions where a temporary object will always be created(from P0135): * when a prvalue is bound to a reference * when member access is performed on a class prvalue * when array subscripting is performed on an array prvalue * when an array prvalue is decayed to a pointer * when a derived-to-base conversion is performed on a class prvalue * when a prvalue is used as a discarded value expression I dont know if any of those exceptions can help in your case. I ran into the same problem with the Fit library, and was unable to find a workaround. It would be nice if compiler could provided the ability to force a temporary object to always be created from a function. Paul
AMDG On 09/28/2017 04:58 PM, Lorenzo Caminiti via Boost wrote:
<snip>
Correctly it does not compile up to C++1y because main cannot access the copy operations:
$ clang++ -std=c++1y 05.cpp 05.cpp:14:15: error: calling a private constructor of class 'x' auto xx = f(); ^ 05.cpp:5:5: note: declared private here x(x const&) {} ^ 1 error generated.
However, it compiles on C++1z?!
$ clang++ -std=c++1z 05.cpp # Not compiler errors?!
Why... what changed in C++1z that makes the above compile? How can I prevent copying x outside its friend function f in C++1z?
This code no longer makes a copy, and does not require the copy constructor. In Christ, Steven Watanabe
participants (6)
-
Andrzej Krzemienski
-
Edward Diener
-
Lorenzo Caminiti
-
Niall Douglas
-
paul
-
Steven Watanabe