How to count the number of CRTP subclasses of a template class? - c++

Does anyone know of a method to use CRTP to count the number of subclasses of an object?
Suppose we had a setup similar to the following one:
template <typename T>
class Object
{
....
};
const unsigned int ObjectSubClassCount = ...;
class Subobject : public Object<SubObject>
{
....
};
class Second : public Object<Second>
{
....
};
and so on, such that, using TMP, we might have a constant (ObjectSubClassCount) that represents the total number of subclasses?
Does anyone know a way to do this?
Edit: I am wanting to use the result as a template parameter later on, so I need it to be done with TMP...

Without the requirement to use the result as a template parameter later I would try it doing like this:
// Class which increments a given counter at instanciation
struct Increment {
Increment(std::size_t& counter)
{
counter++;
}
};
// This is your template base
template <typename T>
class Object
{
private:
// For every instanciation of the template (which is done for a subclass)
// the class counter should get incremented
static Increment incrementCounter;
};
// This is the global object counter
static std::size_t classCounter;
// Static Member Variable
template<typename T>
Object<T>::incrementCounter(classCounter);
Haven't tried it but should do. To have the result available as a template parameter again (MPL) I don't have enough experience in MPL but I doubt this is possible.

Ok, so I've come upon a... somewhat acceptable answer.
I figured that it would not work out if the subclasses had absolutely not knowledge of eachother (I mean, we're talking somewhat functional programming...).
Here's a solution for this. It's definitely not the solution I'd wish for; however, it is a start. I've forced all objects to use a form of CRTP, but one that uses more of a linked list format. In this way, our subclasses must be derived from an Object<> templated from:
A: itself
and B: the most recent previously defined subclass
here is my code for this (I use a template from <type_traits> once, just a note)
template <typename T> //SFINAE check for the existance of subclasscount static member
struct has_subclasscount
{
template <typename U>
static typename std::enable_if<sizeof(U::subclasscount) != 0, int>::type test(int);
template <typename U>
static char test(...);
static const bool result = (sizeof(test<T>(0)) == sizeof(int))?(true):(false);
};
template <bool res, typename T>
struct return_subclasscount //the value to return is 0 if false
{
static const int result = 0;
};
template <typename T>
struct return_subclasscount<true, T> //returns subclasscount only if the first parameter is true
{
static const int result = T::subclasscount;
};
template <typename T> //combines return_subclasscount and has_subclasscount
struct get_subclasscount
{
static const int result = return_subclasscount<has_subclasscount<T>::result, T>::result;
};
template <typename This, typename Prev>
class Object
{
public:
static const int subclasscount = 1 + get_subclasscount<Prev>::result; //the subclass count
};
class sub1 : public Object<sub1, int>
{
};
class sub2 : public Object<sub2, sub1>
{
};
class sub3 : public Object<sub3, sub2>
{
};
These last 3 empty classes are the subclasses that we're counting. This is our header file.
In our main .cpp file, we have:
int main() {
std::cout << sub3::subclasscount;
char c;
std::cin >> c;
}
Running it, we get a simple output of:
3
Which confirms that it has worked.
Now, some of the downsides to this solution is:
We must know what our last defined subclass was, before we add on.
We must keep up with anywhere we use the subclass counter, always modifying it to be from the last subclass in the list (this can be averted by using a consistant "endoflist" subclass, which would need to be maintained instead)
Upsides, though, include the fact that we do not need to upkeep any of our previously defined subclasses. However, I consider this answer more of a "starting point" than a "final solution"; perhaps something that can be expanded upon?
(also, this can easily be abused to make a form of tree structure, where subclasscount would actually represent the depth of any given node in the tree)
Anyone have any ideas from here?

Related

can C++ template detect members of specific type?

can C++ template detect members of specific type? As code below,
template <typename T>
class Element {
};
template <typename T>
class Container {
public:
Container() {
// check if T has member which type is "Element<whatever>"
// how many Element<whatever>s?
// offset?
}
};
I have a template class named Container, and I want to check:
If the passed in type T has member which type is Element<whatever>?
If so, can I get how many members which type is Element<whatever>?
If so, can I get the offset to the beginning of the class?
Explain more about requirement 3:
What I want is to access these fields(if exist) when I get a piece of data which is cast by reinterpret_cast<T>
This is doable in C++20 if the T of Container<T> is an aggregate ; I use the boost::pfr library as it simplifies this idiom but it is easily reimplementable by hand (boost::pfr's source is very simple to read)
#include <boost/pfr.hpp>
template<typename T, typename Target>
auto count_members_of_type()
{
unsigned int count = 0;
boost::pfr::for_each_field<T>(T{}, [&] <typename U> (U&&) {
count += std::is_same_v<std::remove_reference_t<U>, Target>;
});
return count;
}
given
struct Foo {
Element<int> a, b;
Element<float> c;
std::string d;
};
then
count_members_of_type<Foo, Element<int>>() == 2
Running example on gcc.godbolt.org: https://gcc.godbolt.org/z/srhn8GfWb

How do I implement inheritance in a partial class template specialisation?

I think I'm just missing something small. I want to specialize the constructor of a templated class for an implementation where T = the template class with any parameter. Sorry if my vocab is a bit off.
Basically, I need to allow for jagged 2D arrays, so I might have a ArEl<ArEl<int>> and I would like to preinitialise all the array lengths.
using namespace std;
template <typename T>
class ArEl {
public:
ArEl(size_t size = 0)
: rSize(size), rArray(rSize ? new T[rSize]() : nullptr) {}
ArEl(const ArEl& other);
virtual ~ArEl() { delete[] rArray; }
void swap(ArEl& first, ArEl& second);
void redim(size_t size);
private:
std::size_t rSize;
T* rArray;
};
template <typename T, typename T1>
class ArEl<ArEl<T>> : public ArEl<T1>{
ArEl(size_t size = 0);
};
EDIT:
I'm getting this error:
error: template parameters not deducible in partial specialization:
class ArEl<ArEl<T>> : public ArEl<T1>{
You're specializing your object in the wrong way.
template<typename T, typename T1> implies that there's two datatypes that need to be provided, but it's clear that the only thing your template specialization needs is the datatype of the underlying array(s). If the expectation is that ArEl<ArEl<T>> be specialized, it shouldn't take more than this:
template<typename T>
class ArEl<ArEl<T>> {
/*Blah Blah Blah*/
};
There's no need for inheritance, and no need for a second datatype.
However, I'll also add: there's not really any need for this specialization in the first place. If you don't write the specialization at all, the following code should still work as-is:
ArEl<ArEl<int>> dim2Array(50);
//I'm assuming ArEl will have a member size() function
for(size_t index = 0; index < dim2Array.size(); index++) {
//I'm assuming ArEl will have an operator[] overload
dim2Array[index].redim(30);
}
//dim2Array is now 50 int arrays, each of size 30.
I'm assuming that the functionality you're intending is to have something like the following, which does require template specialization like what I posted above:
ArEl<ArEl<int>> dim2Array(50, 30);
//dim2Array is now 50 int arrays, each of size 30.
But if I were you, I'd leave the implementation of ArEl alone and instead invest in writing a Matrix<T> class (or possibly Matrix<T, N>, for N-dimensions) that handles this kind of syntax instead (which you could build using ArEl<T> as the building blocks, incidentally), especially because I don't think you're committed to writing the specializations for ArEl<ArEl<ArEl<int>>> or deeper (and yes, the way you're trying to do it, each level would need its own specialization).
Specializing an entire class implies replacing all the members with the ones provided by the specialization. You don't want that.
One option would be to provide all the members that need specialization in a base class: BaseForA<T> would be specialized, and A<T> would derive from it.
Another one would be to use tag dispatching, here's an example of how you can use it to do different actions depending on the type parameter.
#include <iostream>
#include <type_traits>
template<typename T>
struct tag {};
template<typename T>
struct A
{
private:
template<typename U>
A(std::size_t s, tag<A<U>>)
{
std::cout << "special constructor " << s << "\n";
}
A(std::size_t s, ...)
{
std::cout << "general constructor " << s << "\n";
}
public:
A(std::size_t s = 0) :
A(s, tag<T>())
{
}
};
int main()
{
A<int> a;
A<A<int>> b;
A<A<long>> c;
A<long> d;
}
Live on Coliru
If I understand you correctly you want the specialised version to inherit the generic version and then add something on top of it. The problem here is that you have a specialised ArEl<ArEl<T>>, you cannot request a generic version of it.
The solution is to make the generic version and the specialised version be different types.
template<typename T, bool D=true>
class ArEl { ...
template<typename T>
class ArEl<ArEl<T>>:
public ArEl<ArEl<T>, false> { ...
But now the problem is that ArEl<T, true> and ArEl<T, false> are unrelated and incompatible!
The solution is to introduce a common base class for them.
template<typename T>
class ArElBase {
... all functionality of ArEl
};
template<typename T, bool D=true>
class ArEl : public ArElBase<T> {
using ArElBase<T>::ArElBase;
// nothing more
};
and then the specialisation, unchanged.
Now you can use ArElBase to pass your objects by pointer or reference, but use ArEl to declare objects themselves.

C++ How to extend a template to work with vector<T>

unfortunately my actual template is too full of stuff that is unrelated to my question, so i tried to put everything in a short example. Lets say, I have written the following template:
#include <vector>
template <typename T> class MyTemplate{
public:
typedef void(*MyFunc)(T);
void addFunc(MyFunc f){myFuncs.push_back(f);}
void callFuncs(T value){
for (std::size_t i=0;i<myFuncs.size();i++){myFuncs[i](value);}
}
private:
std::vector<MyFunc> myFuncs;
};
I learned already, that I can specialize this template to behave different when the passed type is a vector, so I wrote this:
template <typename T> class MyTemplate<std::vector<T> > {
public:
typedef void(*MySingleElementFunc)(T);
void addSingleElementFunc(MySingleElementFunc f){
this->mySingleElementFuncs.push_back(f);
}
void callFuncs(std::vector<T> value){
//for (std::size_t i=0;i<myFuncs.size();i++){
// myFuncs[i](value);
//}
for (std::size_t i=0;i<mySingleElementFuncs.size();i++){
for (int size_t i=0;i<value.size();i++){
mySingleElemetnFuncs[i](value[i]);
}
}
}
private:
std::vector<MySingleElementFunc> mySingleElementFuncs;
};
Now my question is, what is the most elegant way (if possible without inheritance) not only to specialize the template for the case of vector< T > but at the same time still being able to use the first templates methods where vector< T > is the template parameter. What I would like to do later is the following
void Func1(int i){}
void Func2(std::vector<int> i){}
MyTemplate<std::vector<int> > myTemplate;
myTemplate.addFunc(Func1);
myTemplate.addFunc(Func2);
Is it possible to achieve this without simply copy&paste all stuff I need from the original template, to do the same also with the specialized version? I guess I will have to use some kind of inheritance. However, I want to avoid something like this:
MyTemplate<std::vector<int> > myTemplate;
// myTemplate.addFunc(Func1); // does not work
myTemplate.addFunc(Func2);
MyVectorTemplate<std::vector<int> > myVectorTemplate;
myVectorTemplate.addFunc(Func1); // works
myVectorTemplate.addFunc(Func2);
i.e. the functionality should be determined only by the type passed to the template but not by choosing the appropriate subclass. Anyhow, I have to admit that I am a bit confused about how to inherit in this case. If it was not a template, I could write something like
class MyVectorClass : public MySingleObjectClass {}
However, the following does not make any sense:
template <typename T> MyTemplate<std::vector<T> > : public MyTemplate<std::vector<T> >
but in some sense, this is what I would like to have.
I am sorry for such a long post and I hope it is more or less clear what is my problem...
EDIT: I just found a mistake in the above code. The loop in the vector template should read
for (std::size_t i=0;i<mySingleElementFuncs.size();i++){
for (int size_t j=0;j<value.size();j++){
mySingleElemetnFuncs[i](value[j]);
}
}
i.e. each registered function should be called once for each entry in the vector. (Otherwise the template does not work if the number of registered functions is not equal to the size of the vector.)
In fact you want add functionality to the specialization, something like:
template <typename T> class MyTemplate<std::vector<T> >
{
public:
typedef void(*MySingleElementFunc)(T);
typedef void(*MyVectorFunc)(std::vector<T>);
void addSingleElementFunc(MyVectorFuncf){
this->myVcetorFuncs.push_back(f);
}
void addSingleElementFunc(MySingleElementFunc f){
this->mySingleElementFuncs.push_back(f);
}
void callFuncs(const std::vector<T>& value){
for (std::size_t i=0;i<myVectorFuncs.size();i++){
myVectorFuncs[i](value);
}
for (std::size_t i=0;i<mySingleElementFuncs.size();i++){
for (int size_t i=0;i<value.size();i++){
mySingleElemetnFuncs[i](value[i]);
}
}
}
private:
std::vector<MySingleElementFunc> mySingleElementFuncs;
std::vector<MyVectorFunc> myVectorFuncs;
};
template <typename T>
class MyTemplateBase {
// generic stuff goes here
};
template <typename T>
class MyTemplate : public MyTemplateBase<T> {
// nothing goes here
};
template <typename T>
class MyTemplate<std::vector<T>> : public MyTemplateBase <std::vector<T>> {
// specialized stuff goes here
}
If you don't want public inheritance you can use private inheritance, but then you would have to explicitly export everything inherited privately:
template <typename T>
class MyTemplate<std::vector<T>> : private MyTemplateBase <std::vector<T>> {
public:
// generic stuff re-exported
using MyTemplateBase<std::vector<T>>::Func1;
using MyTemplateBase<std::vector<T>>::Func2;
// specialized stuff goes here
}
Might still be worth it, as public inheritance is not exactly the most appropriate tool for code reuse.
I think that, since Vector is a template not a class, should be something like:
template<template <typename ...> class T /*= std::vector*/>
class SomeClass
{
T x;
};

C++ template class with default parameters, and probably metaprogramming

I went into trouble understanding the following codes:
#include <iostream>
using namespace std;
template <class PixType, bool B = PixType::is>
class Test {
public:
void print() {
cout << "PixType B=false" <<endl;
}
};
template <class PixType>
class Test<PixType,true> {
public:
void print() {
cout << "PixType B=true" <<endl;
}
};
class PT {
public:
static const bool is = false; // here is the magic
};
int main() {
Test<PT> t;
t.print();
}
I have 4 questions:
What's the difference between the first template test class(with <> right after template instead of the class name) and the second one(with <> after class name Test).
Why can two same classes(both are named Test) exist at the same time.
In fact, when the is in class PT is set to be true, the program will print out PixType B=true, otherwise PixType B=false, and I don't know the magic here.
I tried to change the second template Test class to be like:
template <class PixType, bool B= true>
class Test {
public:
void print() {
cout << "PixType B=true" <<endl;
}
};
But the compiler will warn me of name conflict.
I am really new to these template stuff, and got really confused by these lines of codes. And I don't know how to search for this trick. In most articles about C++ templating, they just talk about some basic ideas and usages about template.
Any help will be greatly appreciated.
Point 1 What's the difference between the first template test class(with <> right after template instead of the class name) and the second one(with <> after class name Test).
Response The first one is the main class template definition. The second one is a specialization of the class template where the second parameter of the template is true.
If you didn't have the second one, the first one will be used regardless of whether the second parameter of the template is true or false.
Point 2 Why can two same classes(both are named Test) exist at the same time.
Response In your case, the second one is a specialization of the first one. When you use:
Test<int, true> a;
The compiler knows to use the specialization to generate code for Test<int, true>. When you use:
Test<int, false> b;
The compiler know to use the first one to generate code for Test<int, false>.
Point 3 In fact, when the is in class PT is set to be true, the program will print out PixType B=true, otherwise PixType B=false, and I don't know the magic here.
Response As I explained above, when the second parameter is true, the compiler uses the second class template. Otherwise, it uses the first class template. I hope there is no confusion about that any more.
Point 4 I tried to change the second template Test class to be like:
template <class PixType, bool B= true>
class Test {
public:
void print() {
cout << "PixType B=true" <<endl;
}
};
But the compiler will warn me of name conflict.
Response
Class templates can only be specialized, they cannot be overloaded.
template <typename A, typename B> class C1 {};
template <typename A> class C1 {};
The above is not supported by the language.
template <typename A, typename B> class C1 {};
template <typename A> class C1<A, A*> {};
The above is supported by the language. The second class template is a specialization of the first class template.
What you are trying to do is provide a default value for the second parameter but the name used to define the class template is same. The second one is a different class template not a specialization of the first class template.

Accessing public static members of a templated class without instantiating the template?

I have a templated class and want to access a public static variable from outside it, but I can't figure out any way to do so without instantiating the template. This code:
template<class T>
class TemplatedClass {
public:
static const int static_member = 10;
};
...
int i = TemplatedClass::static_member;
Produces the following error: "'template class TemplatedClass' used without template parameters."
If I instantiate the class when accessing the variable:
int i = TemplatedClass<int>::static_member;
The error goes away. I would prefer not to have to instantiate a template in a context where it doesn't really make sense with a dummy type argument just to suppress an error. If I have to, what would be the best dummy type to use? I tried <> and <void>, but neither worked.
Can't be done, since specializations might override the value, i.e:
template<class T>
class TemplatedClass : public BaseClass
{
static const int value = 42;
};
template<>
class TemplatedClass<StarTrek>
{
static const int value = 47;
}
Thus you will get different values:
TemplatedClass<StarTrek>::value != TemplatedClass<void>::value
If the values are to be equal, I strongly suggest you add a non-template base class:
class BaseClass {
public:
static const int value = 42;
};
template<class T>
class TemplatedClass : public BaseClass
{
...
}
Instantiating or explicitly a dummy type (i.e. void) might work, but you might get compile errors depending on how you use your template parameter.
int x = TemplatedClass<void>::value;
So, please write code which show your intentions clearly, i.e. common values for all instantiations should not be in the type-dependent template class. If you can't have that, please explain what you're trying to do in more detail.
Using a dummy type might work for trivial classes, but not if things get more complex.
Let's imagine, that your class "continues" like this:
template<class T>
class TemplatedClass {
public:
static const int static_member = 10;
typedef typename std::enable_if< std::is_integral< T >::value >::type type;
};
This code tells us that T cannot be non-integral type.
Upd (thanks to jogojapan):
That's why in some cases you cannot use any type as a dummy one