I want to define a class template Bar<T>, which uses another class template Foo<U>, and the template parameter T is passed as the template argument of Foo<U> somewhere.
Then if U in Foo<U> has some concept constraits (std::floating_point for example), should I repeat the constrait on T when defining Bar?
#include <concepts>
template <std::floating_point U>
struct Foo { /* ... */ };
// <typename T> or <std::floating_point T>?
template <typename T>
struct Bar {
void Func() {
Foo<T> foo; // Uses Foo here
/* ... */
}
};
<typename T> and <std::floating_point T>, what are the benefits and tradeoffs of each version?
Specifying the same constraint in two places is both duplication and a form of coupling.
Therefore you should only do this if it actually fixes or improves something.
You're not using SFINAE and you'll get a reasonable error message when the instantiation of Foo fails anyway, in this case there's no benefit, and some disbenefit. Don't do it.
I would say you have 2 options to be SFINAE friendly,
Either constraint the whole class:
template <std::floating_point U>
struct Foo { /* ... */ };
template <std::floating_point T>
struct Bar {
void Func() {
Foo<T> foo; // Uses Foo here
/* ... */
}
};
or, constraint only the method:
template <std::floating_point U>
struct Foo { /* ... */ };
template <typename T>
struct Bar {
void Func() requires(std::floating_point<T>) {
Foo<T> foo; // Uses Foo here
/* ... */
}
};
Which one is the most adapted would depend of the purpose of the classes/methods
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With