Home > front end >  Concept requirement and non-immediate context
Concept requirement and non-immediate context

Time:02-02

I'm learning C concepts, and trying to realize why the following does not compile (it's just a trivial and meaningless example demonstrating the point; tested with GCC-11.1):

#include <iostream>

struct non_negatable {
};

template <class T>
auto negate(T a) {
    return -a;
}

template <class T>
concept is_negatable = requires(T t) {
    //just `-a;` would do the job of course
    negate(t);
};

template <class T>
auto do_negate(T) {
    std::cout << "here we are\n";
}

template <is_negatable T>
auto do_negate(T t) {
    return negate(t);
}

int main() {
    non_negatable x;
    do_negate(x);
}

The above concept attempts to call a function template, whose implementation would not compile. This fact causes a "hard error", rather than failing the concept.

I guess it works this way because the concept requirements may be failed only by the expressions' "immediate context" ill-formness (like what we could observe with SFINAE).

Is my understanding correct? Where does the Standard describe this point? Is there a way to "fail" a concept based on a function template implementation ill-formness?

CodePudding user response:

Firstly, as you referred, negate<non_negatable> is not a substitution failure since the error is not in the immediate context of the function, as such it's ill-formed. From 13.10.3.1/8 of C 20 standard:

If a substitution results in an invalid type or expression, type deduction fails.

An invalid type or expression is one that would be ill-formed, with a diagnostic required, if written using the substituted arguments.

[Note 4: If no diagnostic is required, the program is still ill-formed. Access checking is done as part of the substitution process. — end note]

Only invalid types and expressions in the immediate context of the function type, its template parameter types, and its explicit-specifier can result in a deduction failure.

[Note 5: The substitution into types and expressions can result in effects such as the instantiation of class template specializations and/or function template specializations, the generation of implicitly-defined functions, etc. Such effects are not in the “immediate context” and can result in the program being ill-formed. — end note]

Secondly, 7.5.7.1/6 says:

[...]

[Note 1: If a requires-expression contains invalid types or expressions in its requirements, and it does not appear within the declaration of a templated entity, then the program is ill-formed. — end note]

[...]

So, your understanding seems correct to me. However, what you're asking in your last question boils down to whether there is a way to make an invalid expression in a template function body cause a substitution failure instead of an ill-formed program. I don't think it's possible.

  •  Tags:  
  • Related