|
|
|
|
|
by jcelerier
1492 days ago
|
|
I really don't see in which way the second case is less verbose especially if you add a non-void return type, e.g. i32. The first case would also be doable like this, which is pretty munch the exact same than your first example with the added "template" keyword template<std::floating_point T>
void func(T t) { ... }
(also, it's not really equivalent - if I'm not mistaken with traits you can only use what the trait declares ; in C++ you can for instance do something like template<typename T>
concept CanBlah = requires (T t) {
t.blah();
};
and still be able to do void func(CanBlah auto t) {
log << "func:" << t;
t.blah();
}
instead of polluting the prototype with all possible side concerns) |
|
C++ Concepts are duck typed, and Rust's Traits are not, so in Rust you are expressing meaning here, and in C++ only making some claims about syntax which perhaps hint at meaning.
WG21 seems to dearly wish this wasn't so, offering Concepts which pretend to semantics they don't have, such as std::totally_ordered and I'm glad to see your "CanBlah" concept doesn't do this, to be sure all things which match this requirement can, indeed blah() although we've no idea what that can or should do.
Once you've accepted that you only have duck typing anyway, you're probably going to have to explain in your documentation the actual requirements for this parameter t, as the prototype merely says it CanBlah and that's not actually what we care about.
In contrast the Rust function we looked at actually does tell us what is required here, something which "implements FloatingPoint", and that implementation (plus the data structure itself) is all that's being exposed.