-
Notifications
You must be signed in to change notification settings - Fork 249
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BUG] Improve cpp2::in
(restore old behavior, exclude problem cases only)
#317
Comments
Here's a table to visualize the
The first column uses ❌ for the bad cases before a89af8f.
a89af8f's commit message mentions:
In no discussion was it even hinted at to also disregard the size part from the convention:
As shown in the table, since a89af8f,
Bonus points: #317 (comment). |
prefer_pass_by_value
and enhance to exclude problematic casescpp2::in
(restore old behavior, exclude problem cases only)
Based on the discussion at a89af8f#r107115865 and below, I propose this new formulation for template<typename T>
constexpr bool prefer_pass_by_value =
sizeof(T) <= 2*sizeof(void*)
&& std::is_trivially_copy_constructible_v<T>;
template<typename T>
requires std::is_class_v<T> || std::is_union_v<T> || std::is_array_v<T> || std::is_function_v<T>
constexpr bool prefer_pass_by_value<T> = false;
template<typename T>
requires (!std::is_void_v<T>)
using in =
std::conditional_t<
prefer_pass_by_value<T>,
T const,
T const&
>; |
Unfortunately, it doesn't look like https://en.cppreference.com/w/cpp/types/is_copy_constructible
Maybe the requires qualified version is enough to block everything that isn't those types. If so, then maybe this would work too.
|
You must exclude the cases where |
So that's the reason for the two versions, there's no short-circuiting there, and Nope, also need Also doesn't handle |
See a89af8f#r107716660. Can you prove they affect |
@JohelEGP I have done a small test with your proposed solution: https://godbolt.org/z/qnYaYcxPM auto fun(in<int>) {} // works
auto fun(in<S>) {} // works
auto fun(in<C>) {} // works
auto fun(in<E>) {} // works
auto fun(in<U>) {} // works
auto fun(in<A>) {} // fails, but works with std::is_scalar_v
auto fun(in<AS>) {} // fails, but works with std::is_scalar_v
auto fun(in<V>) {} // fails, need to add requires (!std::is_void_v<T>) |
We can only try to declare them: https://godbolt.org/z/sn11YdY6f auto fun(in<int>); // works
auto fun(in<S>); // works
auto fun(in<C>); // works
auto fun(in<E>); // works
auto fun(in<U>); // works
auto fun(in<A>); // fails, but works with std::is_scalar_v
auto fun(in<AS>); // fails, but works with std::is_scalar_v
auto fun(in<V>); // fails, need to add requires (!std::is_void_v<T>) The types might comes from cpp1 we might don't know what they are alias for, or it just might be inside some generic code (that is why I have tested it against |
TLDR: currently (probably) the most reliable version is: template<typename T>
requires (!std::is_void_v<T>)
using in =
std::conditional_t<
std::is_scalar_v<T>,
T const,
T const&
>; |
You may be right about See https://compiler-explorer.com/z/Tq65osnof. auto fun(in<A>) {} // works
auto fun0(A) { }
void g(A a) { fun0(a); } // works
auto fun(in<AS>) {} // works? should it?
auto fun1(AS) { }
void g(AS a) { fun1(a); } // works
auto fun(in<V>) {} // works, should it?
auto fun2(void) { } // works
void g() { fun2(); } So those work, but not when going through |
I thought a bit more.
I'll amend #317 (comment). See https://compiler-explorer.com/z/K1TsT7aeG. |
As a parameter,
I'll amend #317 (comment). See https://compiler-explorer.com/z/TEe98e171. |
Made #317 (comment) table shorter and nicer, and added:
Test the columns at https://compiler-explorer.com/z/d3x3TfGP7. |
https://en.cppreference.com/w/cpp/language/function#Parameter_list mentions As expected, a function type broke Following the logic of #317 (comment), I'll amend #317 (comment) and #317 (comment). See https://compiler-explorer.com/z/GevMPo65K.
|
Thank you everyone for participating. I think my solution is ready, and much better that what I could've cooked up alone. I'll leave it to Herb to decide what to take from my and other's raised points. |
Is there a PR somewhere? I can test it “in the field”. |
You can apply this git-patch. diff --git a/include/cpp2util.h b/include/cpp2util.h
index 23a78bc..c1147a1 100644
--- a/include/cpp2util.h
+++ b/include/cpp2util.h
@@ -492,9 +492,19 @@ template<typename T>
//-----------------------------------------------------------------------
//
template<typename T>
+constexpr bool prefer_pass_by_value =
+ sizeof(T) <= 2*sizeof(void*)
+ && std::is_trivially_copy_constructible_v<T>;
+
+template<typename T>
+ requires std::is_class_v<T> || std::is_union_v<T> || std::is_array_v<T> || std::is_function_v<T>
+constexpr bool prefer_pass_by_value<T> = false;
+
+template<typename T>
+ requires (!std::is_void_v<T>)
using in =
std::conditional_t <
- std::is_scalar_v<T>,
+ prefer_pass_by_value<T>,
T const,
T const&
>; |
Amended #317 (comment) with a row for
|
Thanks! I've taken a slight variation of this -- please check the commit, and please reopen this issue if I missed something. (General note: I'm distracted with the upcoming WG21 Varna meeting and will be slow to follow up on issues/PRs until after that.) |
The separate specialization was to avoid using |
But we still know whether the incomplete type is a class, union, or function type, correct? That information has to be part of the forward declaration. |
Correction: Ah, now I see the problem. Thanks! Pushing a fix to go back to your way of doing it... |
Restore a `pass_by_value` computation, but exclude class/union/array/function types. See comment thread in hsutter#317 for details. Also don't allow the Cpp1 casts, and emit migration usability diagnostics for attempts to use them.
Describe the bug
Also fix
<
to<=
to consider types exactly the size of 2 object pointers. See https://compiler-explorer.com/z/8EKPMrhee.The text was updated successfully, but these errors were encountered: