I have two template member functions that should be called based on meeting a constraint (being derived from a specific type)
I have the general case template function called addScheme
defined as follows:
template <typename Field>
template <typename Scheme>
void TransportEquation<Field>::addScheme(Scheme&& scheme) {
if (scheme.needsCorrection()) {
_n_corrected_schemes++;
}
_schemes.emplace_back(std::make_shared<Scheme>(std::forward<Scheme>(scheme)));
}
I added another two functions, for two specific cases.
The first function I have no issues with, the template type Diffusion
should be inherited from IDiffusion
:
template <typename Field>
template <typename Diffusion>
requires std::derived_from<Diffusion, IDiffusion>
void TransportEquation<Field>::addScheme(Diffusion&& diffusion) {
if (diffusion.needsCorrection()) {
_n_corrected_schemes++;
}
auto diff_scheme = std::make_shared<Diffusion>(std::forward<Diffusion>(diffusion));
_diff_scheme = diff_scheme;
_schemes.emplace_back(diff_scheme);
}
My problem is with the other one, in which the scheme should be derived from IConvection<G>
where G
is another template type:
template <typename Field>
template <typename Convection, typename G>
requires std::derived_from<Convection, scheme::convection::IConvection<G>>
void TransportEquation<Field>::addScheme(Convection&& convection) {
if (convection.needsCorrection()) {
_n_corrected_schemes++;
}
auto conv_scheme = std::make_shared<Convection>(std::forward<Convection>(convection));
_conv_scheme = conv_scheme;
_schemes.emplace_back(conv_scheme);
}
This function never gets called, and the general one addScheme(Scheme&& scheme)
always gets called instead. I don't know what is wrong with the function definition and why the constraint is never met?
In case it's useful, this is how I declare IConvection
:
template <typename GradScheme = gradient::LeastSquares>
class IConvection {
// ...
};
and this is a derived type, that never matches the constrain of addScheme(Convection&&)
and addScheme(Scheme&&)
gets called instead:
template <typename G = gradient::LeastSquares>
class Upwind : public IConvection<G> {}
You don't have anything specifying G
, so it isn't deduced, so the template is never matched.
You could add a type alias to IConvection
template <typename GradScheme = gradient::LeastSquares>
class IConvection {
// ...
public:
using gradient_scheme = GradScheme;
};
And then look for that in your requires clause. Any type that lacks a type alias gradient_scheme
doesn't match this template, it isn't a hard error.
template <typename Field>
template <typename Convection>
requires std::derived_from<Convection, scheme::convection::IConvection<typename Convection::gradient_scheme>>
void TransportEquation<Field>::addScheme(Convection&& convection);