Skip to content
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

Concepts that use type traits are inadvertently subsuming them #321

Closed
ericniebler opened this issue Feb 2, 2017 · 6 comments
Closed

Concepts that use type traits are inadvertently subsuming them #321

ericniebler opened this issue Feb 2, 2017 · 6 comments

Comments

@ericniebler
Copy link
Owner

ericniebler commented Feb 2, 2017

In many cases, implementors may want the freedom to implement the concepts directly in terms of the compiler intrinsics that are used to implement the traits. However, by specifying the concepts directly in terms of the type traits, we create a subsumption relationship between the concept and the trait. Implementations no longer have the freedom to not use the trait because that has observable effects on overload resolution.

We propose eliminating the subsumption relationships, thereby giving implementors the freedom to innovate under the as-if rule. This can be done trivially by double-negating the type trait, thereby hiding the subsumption relationship.

@ericniebler
Copy link
Owner Author

ericniebler commented Feb 2, 2017

Proposed Resolution

Change [concepts.lib.corelang.same] as follows:

 template <class T, class U>
 concept bool Same() {
-  return see below ;
+  return is_same<T, U>::value; // see below
 }

-1 Same<T, U>() is satisfied if and only if T and U denote the same
-  type.
+1 There need not be any subsumption relationship between Same<T, U>() and
+  is_same<T, U>::value.

 2 Remarks: For the purposes of constraint checking, Same<T, U>()
   implies Same<U, T>().

Change [concepts.lib.corelang.derived] as suggested in #255.

Change [concepts.lib.corelang.convertibleto] as suggested in #167.

Change [concepts.lib.corelang.integral] as follows:

 template <class T>
 concept bool Integral() {
-  return is_integral<T>::value;
+  return is_integral<T>::value; // see below
 }

+1 There need not be any subsumption relationship between Integral<T>() and
+  is_integral<T>::value.

Change [concepts.lib.corelang.signedintegral] as follows:

 template <class T>
 concept bool SignedIntegral() {
-  return Integral<T>() && is_signed<T>::value;
+  return Integral<T>() && is_signed<T>::value; // see below
 }

+1 There need not be any subsumption relationship between SignedIntegral<T>()
+  and is_signed<T>::value.

@CaseyCarter
Copy link
Collaborator

CaseyCarter commented Feb 2, 2017

This can be done trivially by double-negating the type trait, thereby hiding the subsumption relationship.

That doesn't hide the subsumption, it makes the concept subsume a different (and weird) predicate constraint.

@CaseyCarter
Copy link
Collaborator

CaseyCarter commented Feb 2, 2017

Redirect-through-an-unnamable-trait looks like:

+template <class T, class U>
+constexpr bool __same = is_same<T, U>::value; // exposition only
 
 template <class T, class U>
 concept bool Same() {
-  return see below ;
+  return __same<T, U>;
 }

-1 Same<T, U>() is satisfied if and only if T and U denote the same type.

 2 Remarks: For the purposes of constraint checking, Same<T, U>()
   implies Same<U, T>().
+template <class T>
+constexpr bool __integral = is_integral<T>::value; // exposition only

template <class T>
 concept bool Integral() {
-  return is_integral<T>::value;
+  return __integral<T>;
 }
+template <class T>
+constexpr bool __signed = is_signed<T>::value; // exposition only

 template <class T>
 concept bool SignedIntegral() {
-  return Integral<T>() && is_signed<T>::value;
+  return Integral<T>() && __signed<T>;
 }

It needs more syntax, but avoids naming an exact predicate constraint that users can get a handle on for subsumption.

@ericniebler
Copy link
Owner Author

Can we get away with:

 template <class T, class U>
 concept bool Same() {
-  return see below ;
+  return is_same<T, U>::value; // see below
 }

-1 Same<T, U>() is satisfied if and only if T and U denote the same type.
+1 There is no subsumption relationship between Same<T, U>() and is_same<T, U>::value.

 2 Remarks: For the purposes of constraint checking, Same<T, U>()
   implies Same<U, T>().

@CaseyCarter
Copy link
Collaborator

Yes - that's a good way to avoid increasing specification complexity for this small issue.

@CaseyCarter
Copy link
Collaborator

CaseyCarter commented Mar 5, 2017

LWG prefers to word these as "There need not be any subsumption relationship.." (PR edited in place with that phrasing.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants