I have wrote a gerneric type Meta:
template <size_t N>
struct Meta
{
// ...
};
And I need to make some MetaModifier(s) to build it in compile time.
MetaModifier(s) seem like below:
struct FooModifier
{
template <size_t N, size_t N2>
Meta<N2> apply(Meta<N> meta)
{
// ...
}
};
Some of Modifiers' apply will change Meta<N> to Meta<N2>.
Use case:
constexpr Meta<1> default_meta{};
// Call variadic function
constexpr auto meta = apply_modifiers(default_meta, FooModifier{}, BarModifier{});
This is my implementation:
template <typename Modifier, size_t N>
static constexpr auto apply_modifier(Meta<N> meta, Modifier M)
{
return M.apply(meta);
}
template <size_t N, typename FirstModifier, typename... RestModifiers>
static constexpr auto apply_modifiers(Meta<N> meta, FirstModifier F, RestModifiers... rest)
{
return apply_modifiers(apply_modifier(meta, F), rest...);
}
template <size_t N>
static constexpr auto apply_modifiers(Meta<N> meta)
{
return meta;
}
Currently it works, but I want to check types of Modifier(s) to make sure it has a method Meta<N2> apply(Meta<N>), report a friendly message if it is not matched. I tried to make a concept MetaModifier but failed. How can I write a correct concept or use some compile time checking to ensure it?
UPDATE: Is there a way to try two steps like below (pseudo code)?
template <typename Modifier, size_t N>
static constexpr auto apply_modifier(Meta<N> meta, Modifier M)
{
// First step: test it has a method apply
if constexpr (has_apply<Modifier, Meta<N>>)
{
// Second step: test the return type of apply
auto r = M.apply(meta);
if constexpr (is_meta_type<decltype(r)>)
{
return r;
}
else
{
static_assert(false, "The return type of apply is not Meta<N>");
}
}
else
{
static_assert(false, "Modifier does not have apply method");
}
}
A concept is there to check if a type satisfies some property. It can't check if a template satisfies some property, because a template isn't a type.
apply_modifierneeds to know whichN2to use when it is passed aFooModifier, the easiest way is to makeN2a template argument ofFooModifier.Another possibility is that
N2is dependant onN, e.g.Having done that, we can construct constraints for
apply_modifierandapply_modifiersOur
meta_modifierconcept requires knowing theMetathat it will modify, which means that you can still check modifiers that only apply to certainMetaspecialisations