Discussion:
Shouldn't bodies of a constrained function be 'discarded statements'?
(too old to reply)
s***@raz.email
2017-11-17 16:38:07 UTC
Permalink
I believe the following code should be well-formed:

#include <type_traits>

template<typename x>
std::enable_if_t<sizeof(x) == 4, int> bar()
{
return 1;
}

using T = long int;

int foo() requires sizeof(T) == 4
{
return bar<T>();
}

int foo()
{
return 2;
}

int main()
{
return foo();
}

But as I understand it from P0734r0 (Concepts as they were merged into
C++20), the bodies of functions with unsatisfied requirements are not
discarded, therefore bar<long int> would be instantiated and cause an error.

A possible solution to this would be [expr.prim.id]p4 "A program that
refers explicitly or implicitly to a function with a requires-clause whose
constraintexpression is not satisfied (17.10.2), other than to declare it,
is ill-formed.", but then how would you give the definition of a function
whose constraints are not satisfied?

Is this a defect or am I missing something?
Thanks :)
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Nicol Bolas
2017-11-17 17:37:05 UTC
Permalink
Post by s***@raz.email
#include <type_traits>
template<typename x>
std::enable_if_t<sizeof(x) == 4, int> bar()
{
return 1;
}
using T = long int;
int foo() requires sizeof(T) == 4
{
return bar<T>();
}
int foo()
{
return 2;
}
int main()
{
return foo();
}
But as I understand it from P0734r0 (Concepts as they were merged into
C++20), the bodies of functions with unsatisfied requirements are not
discarded, therefore bar<long int> would be instantiated and cause an error.
Are you allowed to even attach requires clauses to non-template functions?
What you want is a static_assert, not a requires clause.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Daniel Krügler
2017-11-17 17:43:00 UTC
Permalink
Post by Nicol Bolas
Are you allowed to even attach requires clauses to non-template functions?
Yes, a requires-clause is valid for non-template functions as well,
see [dcl.decl] p4 for example.

- Daniel
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Nicol Bolas
2017-11-17 18:03:53 UTC
Permalink
Post by Nicol Bolas
Post by Nicol Bolas
Are you allowed to even attach requires clauses to non-template
functions?
Yes, a requires-clause is valid for non-template functions as well,
see [dcl.decl] p4 for example.
- Daniel
So... what is the behavior of applying a requires clause to a non-template
function? Does the function definition exist or does it not?
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Daniel Krügler
2017-11-17 18:11:52 UTC
Permalink
Post by Nicol Bolas
Post by Daniel Krügler
Post by Nicol Bolas
Are you allowed to even attach requires clauses to non-template functions?
Yes, a requires-clause is valid for non-template functions as well,
see [dcl.decl] p4 for example.
- Daniel
So... what is the behavior of applying a requires clause to a non-template
function? Does the function definition exist or does it not?
According to [expr.prim.id] p4:

A program that refers explicitly or implicitly to a function with a
requires-clause whose constraint-expression
is not satisfied, other than to declare it, is ill-formed.

So how would you validate whether the function exists?

- Daniel
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
s***@raz.email
2017-11-17 18:21:20 UTC
Permalink
You could see if its symbol is exported from the translation unit?
Post by Nicol Bolas
Post by Nicol Bolas
Post by Daniel Krügler
Post by Nicol Bolas
Are you allowed to even attach requires clauses to non-template functions?
Yes, a requires-clause is valid for non-template functions as well,
see [dcl.decl] p4 for example.
- Daniel
So... what is the behavior of applying a requires clause to a
non-template
Post by Nicol Bolas
function? Does the function definition exist or does it not?
A program that refers explicitly or implicitly to a function with a
requires-clause whose constraint-expression
is not satisfied, other than to declare it, is ill-formed.
So how would you validate whether the function exists?
- Daniel
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Daniel Krügler
2017-11-17 18:26:11 UTC
Permalink
Post by s***@raz.email
You could see if its symbol is exported from the translation unit?
This alone is not a proof according to the rules of the language. You
need to show a conforming program that validates this.

- Daniel
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
s***@raz.email
2017-11-17 18:35:56 UTC
Permalink
I don't know if the language actually requires the 'existence' of a
function or what that even means, as compilers delete functions all the
time when optimizing.
I guess the only real "side-effect" of a function being defined but not
used, are the templates it instantiates - this may affect the
well-formedness of the program, therefore a compiler that decides to
"optimize away" a function which is not used because its constraints are
not satisfied thus it can't be used may accept an 'ill-formed' program
because it did not instantiate some template that would cause the program
to be ill formed.
Post by Daniel Krügler
Post by s***@raz.email
You could see if its symbol is exported from the translation unit?
This alone is not a proof according to the rules of the language. You
need to show a conforming program that validates this.
- Daniel
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Nicol Bolas
2017-11-17 19:23:16 UTC
Permalink
Post by Nicol Bolas
Post by Nicol Bolas
Post by Daniel Krügler
Post by Nicol Bolas
Are you allowed to even attach requires clauses to non-template functions?
Yes, a requires-clause is valid for non-template functions as well,
see [dcl.decl] p4 for example.
- Daniel
So... what is the behavior of applying a requires clause to a
non-template
Post by Nicol Bolas
function? Does the function definition exist or does it not?
A program that refers explicitly or implicitly to a function with a
requires-clause whose constraint-expression
is not satisfied, other than to declare it, is ill-formed.
So how would you validate whether the function exists?
You seem to have misunderstood my question. What happens to the function
definition? Does it get compiled or does it not? That's what I mean by
"exist".

Does the sequence of tokens within that function definition have to conform
to legal C++, or does it not?
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Daniel Krügler
2017-11-17 19:56:13 UTC
Permalink
Post by Nicol Bolas
You seem to have misunderstood my question.
Yes, sorry, this seemed to have happened.
Post by Nicol Bolas
What happens to the function
definition? Does it get compiled or does it not? That's what I mean by
"exist".
Does the sequence of tokens within that function definition have to conform
to legal C++, or does it not?
OK, I understand your question now. The mental model is that the body
of a constrained function still has to meet the requirements for legal
C++. I cannot find wording that says otherwise, so the general rules
of function definitions hold.

- Daniel
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Nicol Bolas
2017-11-17 20:10:15 UTC
Permalink
Post by Daniel Krügler
Post by Nicol Bolas
You seem to have misunderstood my question.
Yes, sorry, this seemed to have happened.
Post by Nicol Bolas
What happens to the function
definition? Does it get compiled or does it not? That's what I mean by
"exist".
Does the sequence of tokens within that function definition have to
conform
Post by Nicol Bolas
to legal C++, or does it not?
OK, I understand your question now. The mental model is that the body
of a constrained function still has to meet the requirements for legal
C++. I cannot find wording that says otherwise, so the general rules
of function definitions hold.
But the body of a constrained *template* function only has to be legal C++
if the requirements are actually true. If those requirements aren't true
for some set of parameters, then that function will never be instantiated
with those parameters.

If something similar doesn't work for non-template functions, then what's
the point of applying a requires clause to them?
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Daniel Krügler
2017-11-17 20:38:12 UTC
Permalink
Post by Daniel Krügler
Post by Nicol Bolas
You seem to have misunderstood my question.
Yes, sorry, this seemed to have happened.
Post by Nicol Bolas
What happens to the function
definition? Does it get compiled or does it not? That's what I mean by
"exist".
Does the sequence of tokens within that function definition have to conform
to legal C++, or does it not?
OK, I understand your question now. The mental model is that the body
of a constrained function still has to meet the requirements for legal
C++. I cannot find wording that says otherwise, so the general rules
of function definitions hold.
But the body of a constrained template function only has to be legal C++ if
the requirements are actually true.
From which wording do you derive that assertion? To me that is already
covered by [temp.arg] p6 and [temp.res] p8 and should be ill-formed,
no diagnostics required. If you think the current wording is
insufficient to say that, I would consider this to be a defect.

- Daniel
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Nicol Bolas
2017-11-18 04:42:11 UTC
Permalink
Post by Daniel Krügler
Post by Daniel Krügler
On Friday, November 17, 2017 at 1:11:54 PM UTC-5, Daniel KrÃŒgler
You seem to have misunderstood my question.
Yes, sorry, this seemed to have happened.
What happens to the function
definition? Does it get compiled or does it not? That's what I mean
by
Post by Daniel Krügler
"exist".
Does the sequence of tokens within that function definition have to conform
to legal C++, or does it not?
OK, I understand your question now. The mental model is that the body
of a constrained function still has to meet the requirements for legal
C++. I cannot find wording that says otherwise, so the general rules
of function definitions hold.
But the body of a constrained template function only has to be legal C++
if
the requirements are actually true.
From which wording do you derive that assertion?
Um, none. That's just how I understood Concepts to work. That if the
requires clause evaluates to false, the function "goes away", whatever that
specifically means in standardese.

That's what allows code like this to work:

template<RandomAccessIterator It>
It advance(It it, typename RandomAccessIterator::difference_type advancement
) {return it + advancement;}

template<InputIterator It>
It advance(It it, typename RandomAccessIterator::difference_type advancement
)
{
...
}

Here is how I understood this code to work. If you pass a
random-access-iterator, the first instantiation happens. If you pass a
bidirectional iterator, the implicit requires clause in the first one
fails. The code would be ill-formed if it was instantiated, but that never
happens with a bidirectional iterator; the failed requires clause prevents
it from being instantiated.

Therefore, the compiler moves on to the second one. That function's
requires clause succeeds and therefore can be (and will be) instantiated
with a bidirectional iterator.

Where is my misunderstanding here?
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Daniel Krügler
2017-11-18 12:05:28 UTC
Permalink
Post by Nicol Bolas
Post by Daniel Krügler
Post by Daniel Krügler
Post by Nicol Bolas
You seem to have misunderstood my question.
Yes, sorry, this seemed to have happened.
Post by Nicol Bolas
What happens to the function
definition? Does it get compiled or does it not? That's what I mean by
"exist".
Does the sequence of tokens within that function definition have to conform
to legal C++, or does it not?
OK, I understand your question now. The mental model is that the body
of a constrained function still has to meet the requirements for legal
C++. I cannot find wording that says otherwise, so the general rules
of function definitions hold.
But the body of a constrained template function only has to be legal C++ if
the requirements are actually true.
From which wording do you derive that assertion?
Um, none. That's just how I understood Concepts to work. That if the
requires clause evaluates to false, the function "goes away", whatever that
specifically means in standardese.
template<RandomAccessIterator It>
It advance(It it, typename RandomAccessIterator::difference_type
advancement) {return it + advancement;}
template<InputIterator It>
It advance(It it, typename RandomAccessIterator::difference_type
advancement)
{
...
}
The following question is meant seriously: Is the token sequence "..."
meant literally here in this example or is that just a shortcut for
otherwise "legal C++"?

Note that my reply was specifically referring to your question:

"Does the sequence of tokens within that function definition have to
conform to legal C++, or does it not?"

A concept-constrained C++ code still must be parseable by a compiler,
and that is how I understood your question, because if arbitrary token
sequences would be allowed, this would impose considerable/impossible
requirements onto implementations.
Post by Nicol Bolas
Here is how I understood this code to work. If you pass a
random-access-iterator, the first instantiation happens. If you pass a
bidirectional iterator, the implicit requires clause in the first one fails.
The code would be ill-formed if it was instantiated, but that never happens
with a bidirectional iterator; the failed requires clause prevents it from
being instantiated.
It will not be instantiated, but if we are at the point of deciding
about instantiation, parsing of the code must have succeeded already.
Post by Nicol Bolas
Therefore, the compiler moves on to the second one. That function's requires
clause succeeds and therefore can be (and will be) instantiated with a
bidirectional iterator.
Where is my misunderstanding here?
I think this summarizes it quite well, but that description does not
mean to allow a function body of a rejected constrained function to
contain an arbitrary token soup. Since this depends on the compiler
quality, a diagnostic is allowed but not required.

Does that answer your question?

- Daniel
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Nicol Bolas
2017-11-18 18:25:23 UTC
Permalink
Post by Daniel Krügler
Post by Nicol Bolas
Post by Daniel Krügler
On Friday, November 17, 2017 at 2:56:15 PM UTC-5, Daniel KrÃŒgler
Post by Daniel Krügler
Post by Nicol Bolas
You seem to have misunderstood my question.
Yes, sorry, this seemed to have happened.
Post by Nicol Bolas
What happens to the function
definition? Does it get compiled or does it not? That's what I
mean
Post by Nicol Bolas
Post by Daniel Krügler
Post by Daniel Krügler
Post by Nicol Bolas
by
"exist".
Does the sequence of tokens within that function definition have
to
Post by Nicol Bolas
Post by Daniel Krügler
Post by Daniel Krügler
Post by Nicol Bolas
conform
to legal C++, or does it not?
OK, I understand your question now. The mental model is that the
body
Post by Nicol Bolas
Post by Daniel Krügler
Post by Daniel Krügler
of a constrained function still has to meet the requirements for
legal
Post by Nicol Bolas
Post by Daniel Krügler
Post by Daniel Krügler
C++. I cannot find wording that says otherwise, so the general rules
of function definitions hold.
But the body of a constrained template function only has to be legal
C++
Post by Nicol Bolas
Post by Daniel Krügler
if
the requirements are actually true.
From which wording do you derive that assertion?
Um, none. That's just how I understood Concepts to work. That if the
requires clause evaluates to false, the function "goes away", whatever
that
Post by Nicol Bolas
specifically means in standardese.
template<RandomAccessIterator It>
It advance(It it, typename RandomAccessIterator::difference_type
advancement) {return it + advancement;}
template<InputIterator It>
It advance(It it, typename RandomAccessIterator::difference_type
advancement)
{
...
}
The following question is meant seriously: Is the token sequence "..."
meant literally here in this example or is that just a shortcut for
otherwise "legal C++"?
Legal C++, assuming you provide a type conforming to InputIterator. I just
didn't feel like writing out `std::advance`'s InputIterator form.
Post by Daniel Krügler
"Does the sequence of tokens within that function definition have to
conform to legal C++, or does it not?"
A concept-constrained C++ code still must be parseable by a compiler,
and that is how I understood your question, because if arbitrary token
sequences would be allowed, this would impose considerable/impossible
requirements onto implementations.
By "parseable", are you saying that it has to be C++ grammatically, or that
it must successfully work with the first phase of two-phase lookup? Meaning
essentially that all of the things that aren't dependent on the template
parameters have to actually be there and be correct.

That can cause some unexpected behavior in people's code.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
s***@raz.email
2017-11-17 17:46:28 UTC
Permalink
Well yes I am as mentioned by Daniel.
A static_assert wouldn't allow me to then define another foo().
requires-clauses also affect overload resolution.
Post by Nicol Bolas
Post by s***@raz.email
#include <type_traits>
template<typename x>
std::enable_if_t<sizeof(x) == 4, int> bar()
{
return 1;
}
using T = long int;
int foo() requires sizeof(T) == 4
{
return bar<T>();
}
int foo()
{
return 2;
}
int main()
{
return foo();
}
But as I understand it from P0734r0 (Concepts as they were merged into
C++20), the bodies of functions with unsatisfied requirements are not
discarded, therefore bar<long int> would be instantiated and cause an error.
Are you allowed to even attach requires clauses to non-template functions?
What you want is a static_assert, not a requires clause.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Nevin Liber
2017-11-17 17:50:13 UTC
Permalink
Post by Nicol Bolas
Are you allowed to even attach requires clauses to non-template functions?
Yes.
Post by Nicol Bolas
What you want is a static_assert, not a requires clause.
A static_assert is when you wish to force a compile time error. A requires
clause is when you wish to constrain a function so it is/is not part of the
overload set. They are different things.
--
Nevin ":-)" Liber <mailto:***@eviloverlord.com> +1-847-691-1404
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Thiago Macieira
2017-11-17 23:29:44 UTC
Permalink
Post by Nevin Liber
A static_assert is when you wish to force a compile time error. A requires
clause is when you wish to constrain a function so it is/is not part of the
overload set. They are different things.
A non-template function, even if removed from an overload set, is still
emitted. Any templates it uses will be instantiated.
--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Daniel Krügler
2017-11-17 19:03:57 UTC
Permalink
Post by s***@raz.email
#include <type_traits>
template<typename x>
std::enable_if_t<sizeof(x) == 4, int> bar()
{
return 1;
}
using T = long int;
int foo() requires sizeof(T) == 4
{
return bar<T>();
}
int foo()
{
return 2;
}
int main()
{
return foo();
}
But as I understand it from P0734r0 (Concepts as they were merged into
C++20), the bodies of functions with unsatisfied requirements are not
discarded, therefore bar<long int> would be instantiated and cause an error.
I agree with your interpretation.
Post by s***@raz.email
A possible solution to this would be [expr.prim.id]p4 "A program that refers
explicitly or implicitly to a function with a requires-clause whose
constraintexpression is not satisfied (17.10.2), other than to declare it,
is ill-formed.", but then how would you give the definition of a function
whose constraints are not satisfied?
Is this a defect or am I missing something?
I don't think that this is a defect. I think your example could be
rewritten into a different form using constexpr if and it has the same
effects:

#include <type_traits>

template<typename x>
std::enable_if_t<sizeof(x) == 4, int> bar()
{
return 1;
}

using T = long int;

int foo()
{
if constexpr (sizeof(T) == 4) {
return bar<T>();
} else {
return 2;
}
}

int main()
{
return foo();
}

Note that we have in foo the first substatement being a discarded
statement (assuming sizeof(long) != 4), but the rule you seem to be
applied for constrained functions here, is not relevant in this
context, because [stmt.if] 2 specifically says:

"During the instantiation of an enclosing templated entity (Clause
17), if the condition is not value-dependent after its instantiation,
the discarded substatement
(if any) is not instantiated."

But there is no enclosing templated entity involved in either this or
your original example, therefore the examples are both ill-formed,
which looks consistent to me.

- Daniel
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
s***@raz.email
2017-11-17 19:26:18 UTC
Permalink
There is a note right after your quote: [stmt.if]p2: "[ Note: Odr-uses
(6.2) in a discarded statement do not require an entity to be defined. —
end note ]" - so the two are not equivalent.
And I could enclose both snippets with a class template and instantiate it
- the two examples would then not be equivalent with regards to templates
being instantiated.
Post by s***@raz.email
Post by s***@raz.email
#include <type_traits>
template<typename x>
std::enable_if_t<sizeof(x) == 4, int> bar()
{
return 1;
}
using T = long int;
int foo() requires sizeof(T) == 4
{
return bar<T>();
}
int foo()
{
return 2;
}
int main()
{
return foo();
}
But as I understand it from P0734r0 (Concepts as they were merged into
C++20), the bodies of functions with unsatisfied requirements are not
discarded, therefore bar<long int> would be instantiated and cause an
error.
I agree with your interpretation.
Post by s***@raz.email
A possible solution to this would be [expr.prim.id]p4 "A program that
refers
Post by s***@raz.email
explicitly or implicitly to a function with a requires-clause whose
constraintexpression is not satisfied (17.10.2), other than to declare
it,
Post by s***@raz.email
is ill-formed.", but then how would you give the definition of a
function
Post by s***@raz.email
whose constraints are not satisfied?
Is this a defect or am I missing something?
I don't think that this is a defect. I think your example could be
rewritten into a different form using constexpr if and it has the same
#include <type_traits>
template<typename x>
std::enable_if_t<sizeof(x) == 4, int> bar()
{
return 1;
}
using T = long int;
int foo()
{
if constexpr (sizeof(T) == 4) {
return bar<T>();
} else {
return 2;
}
}
int main()
{
return foo();
}
Note that we have in foo the first substatement being a discarded
statement (assuming sizeof(long) != 4), but the rule you seem to be
applied for constrained functions here, is not relevant in this
"During the instantiation of an enclosing templated entity (Clause
17), if the condition is not value-dependent after its instantiation,
the discarded substatement
(if any) is not instantiated."
But there is no enclosing templated entity involved in either this or
your original example, therefore the examples are both ill-formed,
which looks consistent to me.
- Daniel
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Daniel Krügler
2017-11-17 19:36:54 UTC
Permalink
Post by s***@raz.email
There is a note right after your quote: [stmt.if]p2: "[ Note: Odr-uses
(6.2) in a discarded statement do not require an entity to be defined. — end
note ]" - so the two are not equivalent.
Which two things are not equivalent? The fact that discarded
statements being within or being not within templated entities have
differently rules is by design and not an oversight. The fact that the
content of a discarded statement is not odr-used is not equivalent of
saying that it the compiler is not supposed to validate it. Being not
odr-used just means that it is not necessary, that a referenced entity
within that discarded statement may not be defined. The following
revised example shows a well-formed program (assuming sizeof(T) != 4):

int bar(); // Declared but not defined

using T = long int;

int foo()
{
if constexpr (sizeof(T) == 4) {
return bar();
} else {
return 2;
}
}

int main()
{
return foo();
}

Nonetheless the compiler is required to parse the discarded statement.

- Daniel
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
s***@raz.email
2017-11-17 19:42:02 UTC
Permalink
OK, so the following two programs are not equivalent:
int bar(); // Declared but not defined

using T = long int;

int foo()
{
if constexpr (sizeof(T) == 4) {
return bar();
} else {
return 2;
}
}

int main()
{
return foo();
}

int bar(); // Declared but not defined

using T = long int;

int foo() requires(sizeof(T) == 4) {
return bar();
}

int foo() {
return 2;
}

int main()
{
return foo();
}

Which I believe is confusing.
Again, the second snippet here and the snippet in the OP are both
ill-formed right now, my argument is that they shouldn't be, and have
equivalent semantics to a discarded if.
Post by Daniel Krügler
Post by s***@raz.email
There is a note right after your quote: [stmt.if]p2: "[ Note: Odr-uses
(6.2) in a discarded statement do not require an entity to be defined. —
end
Post by s***@raz.email
note ]" - so the two are not equivalent.
Which two things are not equivalent? The fact that discarded
statements being within or being not within templated entities have
differently rules is by design and not an oversight. The fact that the
content of a discarded statement is not odr-used is not equivalent of
saying that it the compiler is not supposed to validate it. Being not
odr-used just means that it is not necessary, that a referenced entity
within that discarded statement may not be defined. The following
int bar(); // Declared but not defined
using T = long int;
int foo()
{
if constexpr (sizeof(T) == 4) {
return bar();
} else {
return 2;
}
}
int main()
{
return foo();
}
Nonetheless the compiler is required to parse the discarded statement.
- Daniel
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Daniel Krügler
2017-11-17 19:49:12 UTC
Permalink
Post by Daniel Krügler
int bar(); // Declared but not defined
using T = long int;
int foo()
{
if constexpr (sizeof(T) == 4) {
return bar();
} else {
return 2;
}
}
int main()
{
return foo();
}
int bar(); // Declared but not defined
using T = long int;
int foo() requires(sizeof(T) == 4) {
return bar();
}
int foo() {
return 2;
}
int main()
{
return foo();
}
Which I believe is confusing.
Again, the second snippet here and the snippet in the OP are both ill-formed
right now, my argument is that they shouldn't be, and have equivalent
semantics to a discarded if.
OK, this is now a better motivating example than the OP and it gives
to me a different understanding what you were intending to request.

I tend to agree that both examples should behave equivalent.

- Daniel
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Continue reading on narkive:
Loading...