I have a piece of C# code as below:
class Foo<T> where T : TClass
{
// body
}
Is there any standard method I can achieve that generic type constraint in C++
I have a piece of C# code as below:
class Foo<T> where T : TClass
{
// body
}
Is there any standard method I can achieve that generic type constraint in C++
template<class T>
requires (std::is_base_of_v<TClass,T>)
class Foo{
};
Note this is not an exact match, because Foo<A> and Foo<B> are unrelated types in C++. Generics and Templates remain different features with some similar use cases.
The full emulation of Generics requires a base class with virtual methods that does a pile if typecasting boilerplate and derived templates that override and implement some details in my experience. (OTOH, that isn't always needed, and templates do other things easier than Generics do).
C++ has std::is_base_of, which can be used with SFINAE (C++17 and earlier) or requirements (C++20). C++20 also adds the concept std::derived_from.
C++17:
#include <type_traits>
#include <cstddef>
template<class T, std::enable_if_t<std::is_base_of_v<TClass, T>, std::nullptr_t> = nullptr>
class Foo
{
// Body
};
C++20:
#include <type_traits>
template<class T> requires std::is_base_of_v<TClass, T>
class Foo
{
// Body
};
C++14 and C++11 support very similar behavior but with less concise syntax, e.g. replacing std::is_base_of_v<TClass, T> with std::is_base_of<TClass, T>::value.
In C++, we rarely use base-classes to enable/disable generics. I think this should be evident from the ugly syntax we have had for it, until C++20.
Pre-C++20, you just use the type and if it has everything you want, it should compile fine. Error messages are less than ideal, but it's simple and it works:
template <class T>
class Foo { /* ... */ };
Post-C++20, we have "concepts" which are "named constraints". They are similar to "interfaces" in other languages, but everything is resolved at compile time. The syntax is nicer and you can use them instead of the base class in your example:
template <class T>
concept TClass = ...;
template <TClass T>
class Foo { /* ... */ };