Concepts introduces the notion of the `requires` clause: a boolean expression. C++17 will likely introduce if constexpr, which is a condition based on a constant expression.
Since requirements are by definition constexpr, it makes sense to be able to combine the two with:
Now yes, `requires` clauses are `constexpr`, so it would be possible as is to use them with `if constexpr`:
if constexpr (requires(...) {...})
But there's no need to say the same thing multiple times. With concepts and `if constexpr`, I can very easily see people wanting to use them in tandem, so having shorter syntax is not unreasonable. This is similar to how `concept` also implies `constexpr`, without us explicitly having to say it.
Consider the visual difference between:
if requires(T a) {a.SomeFunc();}
and
if constexpr(requires(T a) {a.SomeFunc();})
One useful thing here is that we often already have the equivalent of `T a` somewhere in the program, so most uses of `if requires` would just have an empty parameter list.
Note that `if requires` would have semantic differences from `if(requires{...})`. The latter is a regular `if` statement that just so happens to use a `requires` expression. The former follows the rules of a true `if constexpr`.
This feature could also be used to give us a way of dealing with the definition checking issue. One of the issues with definition checking is that template implementations that are governed by a concept sometimes want to have optional components. If a type has some function, then it will call it, but types which don't have that function are OK as well. Such things are not listed in the concept's constraints because it is something which all types can fulfill. That is, there is no actual constraint requirement; it is a semantic constraint rather than a syntactic one.
The usual way of definition testing is to match the expressions in the constraint with the dependent expressions used in the template. Those which don't match the constraint requirements are illegal. This would prevent the use of such optional features, since by definition they would not be listed in the constraint requirements.
By wrapping such expressions in an `if requires` clause, we're effectively saying that we are adding to the list of expressions that we permit within the template. The reason being that the conditional makes sure that the implementation provides an alternative if the functionality is not present. So if you want to log certain information, and your `Log` function is intended to accept any type, you would do this:
if requires() {Log(a);}
{
Log(a);
}
If it turns out that someone provides some type that uses specializations to prevent `Log` from being called on it, then the `requires` clause will be false and the function will not be called. If you want that to be a compile error, you can still do so:
if requires() {Log(a);}
{
Log(a);
}
else
static_assert(false, "Why did you do that?");
We could improve this by making it require less repetition:
Since a `requires` expression normally needs a parameter list, the use of `if requires` without such a list has special meaning. It should mean that all of the (dependent) expressions in the `if` statement body should be considered part of the `requires` clause. Therefore, if any of those requirements are not met, the `requires` clause yields `false`, and the `else` clause triggers (if any).