I asked this question earlier where a solution was presented. The solution is great as far as the question is concerned, but now I am confused on how I would define the methods outside of the class i.e. I would like to define the methods in an .inl
file. What would be the syntax in this case?
Just to be clear, for a template class, the method definition will be:
template <typename T>
struct Foo
{
Foo();
};
// C-tor definition
template <typename T>
Foo<T>::Foo()
{
}
How would I define methods for the template class with enable_if
as one of the parameters?
template <typename Policy, enable_if< is_base<BasePolicy, Policy>::value >::type >
struct Foo
{
Foo();
};
// C-tor definition -- ???
Templates can be template parameters. In this case, they are called template parameters. The container adaptors std::stack, std::queue, and std::priority_queue use per default a std::deque to hold their arguments, but you can use a different container.
A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.
Template non-type arguments in C++It is also possible to use non-type arguments (basic/derived data types) i.e., in addition to the type argument T, it can also use other arguments such as strings, function names, constant expressions, and built-in data types.
Why we use :: template-template parameter? Explanation: It is used to adapt a policy into binary ones.
Here's how SFINAE can actually work with partial specialization:
template<typename T, typename Sfinae = void>
struct Foo {
/* catch-all primary template */
/* or e.g. leave undefined if you don't need it */
};
template<typename T>
struct Foo<T, typename std::enable_if<std::is_base_of<BasePolicy, T>::value>::type> {
/* matches types derived from BasePolicy */
Foo();
};
The definition for that constructor can then be awkwardly introduced with:
template<typename T>
Foo<T, typename std::enable_if<std::is_base_of<BasePolicy, T>::value>::type>::Foo()
{
/* Phew, we're there */
}
If your compiler supports template aliases (it's a C++11 feature) that then you can cut a lot of the verbosity:
template<typename T>
using EnableIfPolicy = typename std::enable_if<std::is_base_of<BasePolicy, T>::value>::type;
// Somewhat nicer:
template<typename T>
struct Foo<T, EnableIfPolicy<T>> {
Foo();
};
template<typename T>
Foo<T, EnableIfPolicy<T>>::Foo() {}
Note: your original answer referred to utilies from Boost, like boost::enable_if_c
and boost::is_base_of
. If you're using that instead of std::enable_if
and std::is_base_of
(which are from C++11), then usage looks like
typename boost::enable_if<boost::is_case_of<BasePolicy, T> >::type
which has the advantage of getting rid of one ::value
.
From the looks of it, you want to do something along the lines of this:
template <typename Policy,
typename = typename std::enable_if<std::is_base_of<BasePolicy, Policy>::value>::type >
struct Foo;
template <typename Policy>
struct Foo<Policy> {
Foo();
};
template <typename Policy>
Foo<Policy>::Foo() {
}
This sneakily takes advantage of the default argument in a few places: don't get confused, there is an implicit void
sitting in several locations.
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