4 ms·
concepts don't change codegen in any way, they just mean your error messages become actually sane :D Essentially, in the past you would have your template code
by olliej 4y ago
concepts don't change codegen in any way, they just mean your error messages become actually sane :D
Essentially, in the past you would have your template code, say something dumb like:
template <typename T> T halve(T t) { return t / 2; }
and if you instantiated with the wrong type, say:
halve("foo")
you get an error message pointing to the t/2 in the halve implementation. As your templates become less trivial, so do the error messages. So we could apply concepts:
template <typename T> concept Halvable = requires (T t) { t / 2; };
template <Halvable T> T halve(T t) { return t / 2; }
Now our call to halve("foo") will complain that const char* is not Halvable. It will also produce an error similar to the original saying that we don't conform to Halvable because the `t / 2` expression fails. In this case it's not super valuable, but if you were instantiating a type or method that was more complicated instead of getting dozens or hundreds of errors in the instantiated body of the template, you just get an early error saying "you aren't conforming to X for these reasons:...".
Unfortunately this does not stop you writing a template that depends on things that your concepts don't guarantee. For example, if we can halve something, we must be able to double it, right? (silly example to demonstrate the issue)
template <Halvable T> T double_it(T t) { return t * 2; }
Note, Halvable doesn't ensure that * is available, but this template is still "correct".
Now we can do `double_it(1)` and that will work, but `double_it("foo")` will say the error is at the t * 2 in the body, when we probably want the error to actually at the point we try to call double_it.
Preventing this kind of error is non-trivial (possibly actually impossible?) given how concepts are defined. It's literally just a list of statements and expressions that need to be valid for a type. But going from a list of "these statements and expressions are valid" to "is this specific expression or statement valid in a template" is at best nontrivial. This is core limitation of the entire feature.
- ratorx 4y agoArguably, pointing to t/2 (in the second case) is the correct behaviour, because (if concepts are being used), then it is the function (double_it) that is mis-specifying it’s requirements. Even better would be to point at the function definition as well and say that there is nothing in the concept that allows this function. I think the core problem (don’t know if this is still the case, haven’t actually used concepts) is that templates raise errors at the point of expansion, rather than at the point of definition, because of how they are specified/implemented. I think it’s possible that the compiler could do something smart by auto-creating a temp type that is the minimal possible implementation of the concept and attempting to compile the function. Any errors that result, should be flagged at the concept specified in the function.