C++ partial specialization within the inheritance statement? - c++

So I got myself in a pickle with C++ templates. Assuming I got a hierarchy of container-like classes of the form:
template <class T>
class AContainer{
// ...
};
And through inheritance different containers with different internal representations are made:
template <class T>
class AVectorLikeContainer: public AContainer<T>{
// ...
};
And a bunch of hierarchies of operator-like classes which have the form:
template <template <class T> class C, class T>
class AnOperator{
public:
virtual T operator() (const C<T> &c1, const C<T> &c2);
// ...
};
Using inheritance and partial specialization operators like these are made:
template <class T>
class AnOperatorForVectorLike: public AnOperator<AvectorLikeContainer, T>{
public:
virtual T operator() (const AVectorLikeContainer<T> &c1, const AVectorLikeContainer<T> &c2);
// ...
};
Now, a bit later in the project, containers of the form:
template <class T, std::size_t N>
class AStaticSizeContainer: public AContainer<T>{
// ...
};
were introduced. Obviously this sort of breaks the design, since AStaticSizeContainer doesn't match the template <class T> class C part of the template signature of AnOperator. A way to go around this is to introduce a meta-function like so:
template <class T, std::size_t N>
class StaticSizer{
public:
template <class T1>
class SizedStaticContainer: public AStaticSizeContainer<N, T1>{
// ...
};
};
This way, StaticSizer<25>::SizedStaticContainer is a class which matches the template signature template <class T> class C. However, this has a few downsides. The first and obvious one is the need to always use StaticSize<N>::SizedStaticContainer<T> instead of AStaticSizeContainer<T, N> even when T and N are "known". This is caused by the fact that the two are not interchangeable (one is inherited from the other). The second downside is that all constructors of AStaticSizeContainer must be literally copy-pasted for StaticSizer::SizedStaticContainer. I'm sure there are more that I've yet to stumble upon.
So, my questions are the following:
Is there a more elegant way to fix this while conforming to the already laid out interface?
In broader terms, can we specify a partial specialization of a class in a more elegant way?
In narrower terms, do we have the syntax to say something like:
template <class T, std::size_t N>
class AnOperatorForStaticSize: public AnOperator<AStaticSizeContainer<with N = N>, T>{
// ...
};
where by AStaticSizeContainer<with N = N>, I refer to a partial specialization of AStaticSizeContainer with the N from the above template.
EDIT
C++11's alias templates apparently will work, but I need a C++03 alternative.

In the early day of C++ people experimented with a variety of similar approaches and none of them worked out. It is possible that based on the experience of the last nearly 20 years a better approach could be devised but it seems that Generic Programming (introduced in the form of STL) provided a working solution which doesn't have any of the problems you describe. The basic idea to the solution is the fundamental approach to solve problems in computer science: introduce an extra level of indirection. Instead of tying structure to operators, you'd implement operators in terms of a generalized access method to the structure. In STL the structures are sequences, the operators are algorithms, and the glue in between are iterators.

Related

Concept of template class in C++20

I'm new in advanced usage of templates and concepts, so here is a liitle bit complex problem:
I have some Traits concept of many traits for each of Source classes:
template<typename _Traits>
concept Traits = requires
{
std::same_as<std::decay_t<decltype(_Traits::token)>, std::string_view>;
};
I have some template class that uses this concept to handle object_one with various traits (for example, half of Source classes returns object_one):
template <concepts::Traits _Traits>
class Object_one_handler final
{
static std::string handle_object(const object_one& obj) {/*...*/}
};
Then I have Objects_handlers concept of handlers for various objects from set {object_one, object_two, object_three} from various Sources with their Traits:
template<template <concepts::Traits _Traits> class _Objects_handlers, typename _Object>
concept Objects_handlers = requires(const _Object& obj)
{
// has handle_object method
{ _Objects_handlers<???????>::handle_object(obj) } -> std::same_as<std::string>;
};
Finally, I creating some database with specified as template parameter Object_handler:
template<concepts::Objects_handlers _handler>
class database
{...};
(Actually all of concepts have additional requirements, but it doesn't matter here)
So problem is in last Objects_handlers concept:
template<template <concepts::Traits _Traits> class _Objects_handlers, typename _Object>
concept Objects_handlers = requires(const _Object& obj)
{
// has handle_object method
{ _Objects_handlers<???????>::handle_object(obj) } -> std::same_as<std::string>;
^^^^^^^
};
I can't check _Objects_handlers method without template parameter (obviously) and I can't properly set the template parameter which must be one of Traits.
How can I do that?
And actually it may be problem in usage of Objects_handlers in template of database class, so one more question: how to use it?
P.S. It can be XY problem or not about concepts at all... Maybe composition with strategy pattern will be more usefull, but still want try to create this maybe useless, but workable concept.
Let's reduce this problem a lot.
template <typename T>
struct C {
void f();
};
Now, your goal is to write a concept that takes any class template (e.g. C) and checks that every specialization of it has a nullary member function named f.
template <template <typename> class Z>
concept HasF = requires (Z<???> z) {
z.f();
};
The problem is - class templates in C++ just don't work like this. Even for a particular class template, like C, you can't require that every specialization has f. There's no way to ensure that like somebody, somewhere, didn't add:
template <> struct C<std::vector<std::list<std::deque<int>>>> { };
All you can do is check that a specific type has a nullary member function named f. And that's:
template <typename T>
concept HasF = requires (T t) { t.f(); };
The type-constraint syntax, template <Concept T>, is only available for concepts that constrain types, not concepts that constrain templates or values.

Checking for template parent class in C++ using SFINAE

I've been learning the concept of SFINAE in C++ recentlly and I am currentlly trying to use it in a project.
The thing is, what I'm trying to do is different than anything I could find, and I can't figure out how to do it.
Let's say I have a template class called MyParent:
template <typename Elem>
class MyParent;
And a non-template class called MyClass, that inherites it, using char as Elem:
class MyClass : public MyParent<char>;
Now, I want to use SFINAE in order to check if a typename inherites MyParent, regardless of what Elem type is used.
I can't use std::is_base_of, because of the parent's template.
I've tried to do the following:
template <typename T>
struct is_my_parent : std::false_type {};
template <typename Elem>
struct is_my_parent<MyParent<Elem>> : std::true_type {};
Now, if I check for is_my_parent<MyParent<Elem>>::value, it gives me true. Which is good.
However, when I check for is_my_parent<MyClass>::value, I recive false. Which kind of makes sence because MyClass isn't actually MyParent<Elem>, but I didn't manage to get what I wanted.
Is there any convenient way to achive such a thing in C++, other than defining is_my_parent for each and every class that inherites from MyParent?
You might do
template <typename T>
std::true_type is_my_parent_impl(const MyParent<T>*);
std::false_type is_my_parent_impl(const void*);
template <typename T>
using is_my_parent = decltype(is_my_parent_impl(std::declval<T*>()));
Demo
Is there any convenient way to achive such a thing in C++, other than defining is_my_parent for each and every class that inherites from MyParent?
There is, but you'll need to use more elaborate meta-programming techniques. Go entirely back to basics, as it were.
template <class C>
class is_my_parent {
using yes = char;
using no = char[2];
template<typename t>
static yes& check(MyParent<t> const*);
static no& check(...);
public:
enum { value = (1 == sizeof check(static_cast<C*>(0))) };
};
It relies on two basic properties of function overloading and templates:
A derived class can be used to match a function template that takes a base class template as an argument.
Ellipsis offer a conversion sequence that is always considered worse than any other.
Then it's just a matter of inspecting the return type of the chosen overload to determine what we got. Other than the type alias, you can even use this in C++03. Or you can modernize it, so long as overload resolution does the work for you, the check will be performed just the same.
I like Jarod42's answer much better, but an actual SNINAE approach somewhat close to your attempt can work. Here's what I came up with.
To use the type_traits to answer this, we need to know the type of the element. We can make MyParent expose it:
template <typename Elem>
class MyParent {
public:
using ElemType = Elem;
};
Then the default (false) is_my_parent takes an extra arg and the void_t technique* can be used:
template <typename T, typename = void>
struct is_my_parent : std::false_type {};
template <typename T>
struct is_my_parent<T, std::void_t<typename T::ElemType>> :
std::is_base_of<MyParent<typename T::ElemType>, T>::type {};
The specialization is only valid if ElemType is an accessible type in T, and then it results in std::true|false type if the inheritance relationship holds.
live example: https://godbolt.org/z/na5637Knd
But not only is the function overload resolution a better approach for simplicity and size, it will also compile much faster.
(*) void_t was exposed to the world in this fantastic 2-part 2014 talk by Walter Brown. Recommended even if only for review.
https://www.youtube.com/watch?v=Am2is2QCvxY

Class template: add extra variable/method for specific typename

I have a scenario where class template seems to work for most cases, but some classes will need to define an extra variable/method for specific typename. Can I achieve this using templates only or should I use inheritance?
Sounds like you want to create a specialization. I arbitrarily chose std::vector as a type for when you wanted special behavior.
template <typename T>
struct Foo
{
// Stuff for most Types
};
template <typename T, typename A>
struct Foo<std::vector<T, A>>
{
// Stuff when the type is a std::vector of some types
};
Note that any common code will have to be duplicated in the specialization, or you may want to use a base class to represent the implementation - I suggest private inheritance if you choose that route.

Why can't you template a template?

In C++ there are 2 template types (to my knowledge): template classes and template functions. Why is it not possible to have a template of template? (be it class, or function, or other template). Has it ever been considered in standards? Does it break C++ syntax/spirit in a way?
I know it may sound crazy, and it's easy to get around.
What is possible with C++:
template<bool b>
class TemplateDependingOnBool
{
public:
template<typename T>
class TheTemplateWeWant{};
}
What would be great:
template<bool b>
template<typename T>
class TheTemplateWeWant{};
and call it in a policy-based style (that's where it's really interesting):
template<typename T, template<typename> class ThePolicy = TheTemplateWeWant<true> >
class Foo {};
The way it's possible to do now is to use:
template<typename T,
template<typename> class ThePolicy = TemplateDependingOnBool<true>::TheTemplateWeWant >
class Foo{};
which is not very elegant.
EDIT:
I know I can template on 2 parameters. The goal is to use the underlying template class (the templated template) as something by itself, be it in a template alias or a template template parameter (as shown in my example).
Policy-based design is a reference to Andrei Alexandrescu's Modern C++ Design, which is the main reason why the feature I'm asking might be useful (because templates are used as template parameters).
With C++11, you're wrong in assuming only two types of templates. There are also type aliases which allow
template <bool b, typename T>
class TheTemplateWeWant { ... };
template<typename T>
using ThePolicy = TheTemplateWeWant<true, T>
If I'm understanding what you're asking correctly (and I'm not entirely clear on your question), then you could write your template taking two parameters:
template <bool b, typename T>
class TheTemplateWeWant { ... };
add a metafunction to partially apply the bool:
template <bool b>
struct PartiallyWant {
template <typename T>
using type = TheTemplateWeWant<b, T>;
};
and then pass that as your policy:
template<typename T,
template<typename> class ThePolicy = PartiallyWant<true>::type >
class Foo { ... };
Foo<char, PartiallyWant<false>::type> foo;
So why not just layer the templates like you propose? The simple answer is that there's no reason to. If TheTemplateWeWant has two template parameters (bool b and typename T, regardless of whether it's an "inner" class or not), then we should express it as such. And if we want to only apply one type or the other, that's something that has fewer use-cases than a general template while also being solvable with just a few lines of boilerplate. Additionally, what if we had such a feature, and now I want to partially apply the T instead of the b? With a few lines of boilerplate I can again accomplish the same thing, but with the layering this would be impossible.
As far as i know you cand you simply that, and it works just as you want - class templated with 2 parameters.
template<bool b, typename T>
class TheTemplateWeWant{}; //valid in C++
What you're describing is partial binding of template parameters, just like std::bind can turn a binary function into a unary function.
For metaprogramming madness, there's Boost.MPL. They do have a template boost::mpl::bind.

Why use a specialised template class?

This occured in the line of thought following Template specialization or conditional expressions?.
I am using template specialisation in a project of mine and came across this example from Stroustrup: Matrix.h, where he declares a MatrixBase template class
template<class T> class Matrix_base
for common elements and a Matrix template class
template<class T = double, int D = 1> class Matrix
as a "prop" (whatever that is) for specialisations. He declares the constructor as private so that only specialisations can be instanciated. These are declared:
template<class T> class Matrix<T,1> : public Matrix_base<T> {...};
template<class T> class Matrix<T,2> : public Matrix_base<T> {...};
template<class T> class Matrix<T,3> : public Matrix_base<T> {...};
My question is: In this case, what is the advantage of specialisation? Obviously there is no code that the three specialisations have in common, so why not cut out the general template and declare:
template<class T> class Matrix_1<T> : public Matrix_base<T> {...};
template<class T> class Matrix_2<T> : public Matrix_base<T> {...};
template<class T> class Matrix_3<T> : public Matrix_base<T> {...};
?
Because by having the second template parameter, one allows for specializations as well as a general, non-specialized implementation. So
Matrix<float, 1000> m;
might do something reasonable but non specialized, whereas you would have to define a Matrix_1000<T>.
Edit: the first point applies in general, but not to this particular case, where the general case has a private constructor.
Furthermore, it allows you to do stuff like
Matrix<double, SOME_CONSTANT> m;
which you cannot do with your _N solution.
Basically the answer is that you can use the template in generic code. You can use a compile time constant to change the behavior of the program, or you can write generic code that will handle different versions of the Matrix class that could not be handled if the types had different names:
template <typename T, int D>
void print( std::ostream& o, Matrix<T,D> const & m ) { ...
That is, even though you need to explicitly create the different types, the specialization mechanism allows you to provide a single name that can be used generically to manage the different types as if they are just variants of one single type.