Reputation: 349
I am stuck into a weird problem of converting Java generics to equivalent C++ templates. Now, I have abstract class in Java defined as below:
template <class T, class K>
public abstract class A<K extends FirstClass<someclass>, T extends SecondClass<? extends anotherclass>> {
Now, in java I know class is assigned to ? on compile time which extends anotherClass. But, in C++ I could not find a way to achieve this. Any helps?
Upvotes: 0
Views: 196
Reputation: 48457
In the declaration of class A
:
public abstract class A<K extends FirstClass<someclass>
, T extends SecondClass<? extends anotherclass>>
the parts K extends FirstClass<someclass>
and T extends SecondClass<? extends anotherclass>
define constraints on generic type parameters K
and T
. This allows to use those types in contexts where one would normally put any concrete type that satisfies the constraints, and at the same time it prevents users from instantiating the class with types that don't.
In C++ this works slightly different. As long as the instantiated parts of a class template are valid when a template parameter is substituted by a template argument, compilation succeeds. You could therefore declare a regular class template with two type template parameters and that will probabaly work fine. However, if you do need a compile-time error if a template type does not satisfy certain conditions, then you can use a static_assert
inside the body of your class.
K extends FirstClass<someclass>
is easy to verify, for that you could use std::is_base_of
.
T extends SecondClass<? extends anotherclass>
is a little bit more complicated, since T
can be derived from any SecondClass
instantiation, whose template type is, in turn, derived from anotherclass
. This can be checked by verifying that a pointer to T
can be implicitly converted to a pointer of type SecondClass<U>*
. Type U
can be deduced from a function call. Once you extract U
, you can again apply the std::is_base_of
trait. void*
can serve as a fallback call parameter if the implicit conversion fails.
Both traits can be implemented as follows:
#include <type_traits>
#include <utility>
template <typename U>
auto T_extends_SecondClass_impl(const SecondClass<U>*) -> std::is_base_of<anotherclass, U>;
auto T_extends_SecondClass_impl(void*) -> std::false_type;
template <typename T>
using T_extends_SecondClass = decltype(T_extends_SecondClass_impl(std::declval<T*>()));
template <typename K>
using K_extends_FirstClass = std::is_base_of<FirstClass<someclass>, K>;
template <typename K, typename T>
class A
{
static_assert(K_extends_FirstClass<K>::value && T_extends_SecondClass<T>::value, "!");
};
Upvotes: 2