Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Equivalent to `<T extends MyClass>` in C++

Tags:

c++

templates

In Java you can define a generic type, that should interhit from anoter, by <T extends MyClass> void myMethod(T item)

Is there an equivalent in cpp? I tried template<class T : Draw_Shape> class MyClass, but dont work.

like image 351
virtual Avatar asked Dec 14 '22 07:12

virtual


1 Answers

When reading below, please be aware that I am not a Java programmer. My knowledge of Java is almost entirely abstract, and possibly out of date. So if Java implemented reification of generics in the last version or two I don't know about it.


So Java Generics and C++ templates share some common syntax and uses, but they are very different things under the hood.

Java Generics are a wrapper of automatically written casts and compile time type checks around a single core type.

C++ templates on the other hand generate new unrelated types for each set of template arguments.

The extends MyClass syntax in Java does two things. First, it permits that "core" type of the generic to know that the T is not merely an Object, but actually a subclass of some interface. This is required for the "core" type to use methods safely (without can-fail-at-runtime dynamic casts).

In C++ this doesn't happen because there is no "core" type generated by a template instantiation. Each template instantiation is independently compiled, and so knows if the operations are valid or not.

The second thing it does is it gives type errors when the wrong type is passed to the generic. The third thing it does is it allows Java to check the Generic code for validity prior to it being instantiated.

For the second, C++ can use concepts (if your compiler is new enough) or use a technique known as SFINAE that is equally powerful, but syntactically awful and honestly its ability to solve this problem was an accident of language development (it is accidentally Turing complete).

For the third, checked templates in C++, it has been proposed many times, but keeps running into compile time performance issues. So there isn't a way to do it in C++, short of instantiating a template.

Solutions:

Do nothing:

No, seriously. Embrace duck typing and don't constrain template parameters. The only big downside is ugly error messages, and rarely "same named operation has different meanings".

static_assert:

template<class T> class MyClass{
  static_assert(std::is_base_of_v<Draw_Shape,T>);
};

this generates clean error messages. There are some downsides in that other code cannot test if MyClass<X> is a valid instantiation without a hard compiler error.

SFINAE:

template<class T,
  std::enable_if_t<std::is_base_of_v<Draw_Shape,T>, bool> =true
>
class MyClass{
};

note that the =true does not compare the test to the value true. It is not ==true. What is going on here is ridiculously complex and annoying; using SFINAE for this purpose is a hack, and this is just a monkey-see monkey-do way to make it clean.

Concepts:

template<class T> requires std::is_base_of_v<Draw_Shape,T>
class MyClass{
};

or

template<std::is_derived_from<Draw_Shape> T>
class MyClass{
};

note that concepts requires a modern C++ complier and std library.

like image 182
Yakk - Adam Nevraumont Avatar answered Dec 30 '22 02:12

Yakk - Adam Nevraumont