Accessing nested template parameters without template template arguments - c++

I have this situation:
template<unsigned int N>
class Base
{
public:
Base(){}
int myint[N];
};
template<unsigned int M>
class BaseWrapper : Base<M>
{
public:
BaseWrapper(){}
};
template<typename T>
class User
{
public:
User(){}
//int myint[T::N]; //How to statically allocate using M or N from above?
};
int main(void)
{
User<BaseWrapper<10> > myuser;
// Do something with User::myint here.
}
I want to be able to use the non-type parameter of the template argument to User to statically allocate data in the User class. I know I can use template template parameters to create BaseWrapper<M> inside User but this is not my preferred approach. Any simple methods to do this?
Thanks!

Add static const unsigned int Size = N; to your class.
Example:
template<unsigned int N>
class Base
{
public:
Base(){}
int myint[N];
static const unsigned int Size = N;
};
Then N is accessible as T::Size in your User class.

Solution 1
Declare a const static member data as:
template<unsigned int M>
class BaseWrapper : Base<M>
{
public:
static const unsigned int size = M; //add this line!
BaseWrapper(){}
};
Then use this as T::size in User class:
template<typename T>
class User
{
public:
User(){}
int myint[T::size]; //you can do this!
};
Solution 2
Or if you cannot add size as member (for whatever reason), then you can use this approach as:
template<typename T> struct get;
template<unsigned int N>
struct get< BaseWrapper<N> > //partial specialization!
{
static const unsigned int size = N;
};
template<typename T>
class User
{
public:
User(){}
int myint[get<T>::size]; //get the size!
};

You can expose the template parameter as a static member variable of the class:
template<unsigned int M>
class BaseWrapper : Base<M>
{
public:
static const int counter = M;
BaseWrapper(){}
};
Then you can use this static member in your User class:
template<typename T>
class User
{
public:
User(){}
int myint[T::counter];
};

The simplest way, which already has been mentioned by the others, is to add a static member to Basewrapper which is initialized to N.
However if for some reason you cannot change User, there's also a way to get at N:
template<typename T> struct get_N;
template<unsigned int N> struct get_N<Basewrapper<N> > { unsigned int const value = N; };
Now in your User template you just can write get_N<T>::value.
One advantage of this is that you can adapt any type after the fact without touching its definition, so if you ever want to instantiate User on anything else than a Basewrapper, say on Newbasewrapper, you just add the line
template<unsigned int N> struct get_N<Newbasewrapper<N> > { unsigned int const value = N; };
or if Newbasewrapper takes some type as template argument and provides the value of N as static const member,
template<typename T> struct get_N<Basewrapper<T> > { unsigned int const value = Basewrapper<T>::N; };

Related

Static polymorphism with constant template

I'd like to have a static polymorphism with the parent class having a template std::array size. This code works fine:
#include <iostream>
#include <array>
using namespace std;
template <size_t size>
class Message
{
public:
size_t GetSize() { return size; }
private:
std::array<uint8_t, size> data_{};
};
class Command : public Message<12>
{
public:
static const size_t kCmdSize{12};
private:
};
class Reply : public Message<16>
{
public:
static const size_t kCmdSize{12};
private:
};
int main()
{
Command cmd{};
Reply rpl{};
cout << "Size: " << cmd.GetSize() << "|" << rpl.GetSize() << endl;
return 0;
}
But I'm not a huge fan of magic numbers.
Is there any way to use a constant declared in the child class as the parameter to the parent class? Something like that:
class Command : public Message<kCmdSize>
{
public:
static const size_t kCmdSize{12};
private:
};
Using this directly attempts to use a variable from a class that doesn't exist yet.
Using C++14.
If you're fine with one extra layer of indirection, then you can use a "traits class" kind of solution:
#include <array>
#include <cstdint>
template <class T> struct MessageSize;
template <std::size_t size>
class Message {
public:
std::size_t GetSize() { return size; }
private:
std::array<std::uint8_t, size> data_{};
};
// Forward declare class for upcoming specialization.
class Command;
// Specialize message size for Command class.
template <> struct MessageSize<Command> {
static constexpr std::size_t size = 12;
};
class Command : public Message<MessageSize<Command>::size> { };
Note that in my example the Message class itself does not use the MessageSize one. You could do that as well, and have Command inherit from Message<Command> instead, but that would make your inheritance tree look a whole lot different (i.e. classes with the same message length wouldn't have the same base class anymore).
You could of course add another layer of indirection in there, where you inherit from e.g. MessageBase<Command> which in turn inherits from Message<MessageSize<Command>::size>.
That's common problem and there is solution used widely, e.g. in implementations of stream components of C++ library. The type definitions and constants related to concrete derived class became part of specialization for a trait class:
template <class T>
struct CommandTrait;
template <class T>
struct Message : public CommandTrait<T>
{
constexpr size_t GetSize() { return this->kCmdSize; } // or Message::kCmdSize, the same in this case
std::array<std::uint8_t, Message::size> data_{};
};
template <size_t _Sz, size_t _CSc = 12 >
struct MessageSize {
static constexpr std::size_t size = _Sz;
static constexpr size_t kCmdSize{ _CSc };
};
template <>
struct CommandTrait<struct Command> : MessageSize<12> {};
template <>
struct CommandTrait<class Reply> : MessageSize<16> {};
class Command : public Message<Command>
{
};
class Reply : public Message<Reply>
{
};
Note that this-> is important to suggest compiler that "kCmdSize" is a name depending on template's parameter. You need a template-dependant name (i.e. qualified for static use or using this-> for runtime). That tells compiler to expect that such name exist or will be existing in future, at time of instantiation. SHould not forget about possibility of using constexpr:
template <class T>
struct Message : public CommandTrait<T>
{
static constexpr size_t GetSize() { return Message::kCmdSize; }
std::array<std::uint8_t, GetSize()> data_{};
};
Trait class may have a common base, but generally type erasure is not required where such structs are used.
How about something like this?
Is there a concern to pass the number from your main-instance instead of letting it hang open in the class impl.
#include <iostream>
#include <array>
using namespace std;
template <size_t size>
class Message
{
public:
size_t GetSize() { return size; }
private:
std::array<uint8_t, size> data_{};
};
template<size_t N>
class Command : public Message<N>
{
public:
static const size_t kCmdSize{N};
private:
};
int main()
{
Command<12> cmd{};
cout << "Size: " << cmd.GetSize() << endl;
return 0;
}

How to get the size of a std::bitset from another class?

Im trying to create a class that has a std::bitset in, and another class is supposed to take it as a parameter and create an std::array getting the size of the std::bitset from the class. Like this:
template<size_t size>
class Individual{
public:
std::bitset<size> data;
};
template<typename Ind>
class Process {
public:
Process() = default;
std::array<OtherType, Ind::data.size()> individuals;//Size of array must be the size of the bitset!
};
But of course this is not working (as you can guess, because data is not static). How to get the size of the std::bitset and put it into the std::array from the second class?
The problem is that during the declaration of Process, it doesn't yet know that Ind is an Individual, so can't do much with it yet. Worse, data is not a static member, so Ind::data doesn't work without an instance of Process. Luckily, there's tons of workarounds, based on your restrictions.
Size as parameter:
template<size_t size>
class Process {
public:
Process() = default;
std::array<OtherType, size> individuals;
};
Or tweak Individual to expose the info you need
template<size_t size>
class Individual{
public:
static const size_t size_ = size; //`static const` is important!
std::bitset<size> data;
};
template<typename Ind>
class Process {
public:
Process() = default;
std::array<OtherType, Ind::size_> individuals;
};
Or as partial specialization:
template<typename Ind>
class Process {
static_assert(sizeof(T)==0, "param must be of type Individual")
//or whatever you want for non-Individual parameters
};
template<size_t size>
class Process<Individual<size>> {
public:
Process() = default;
std::array<OtherType, size> individuals;
};
Or use a partially specialized helper class:
template<class T>
struct size_helper {
static_assert(sizeof(T)==0, "must specialize size_helper");
};
template<size_t size>
class Individual{
public:
std::bitset<size> data;
};
template<size_t size_>
struct size_helper<Individual<size_>> {
static const size_t size = size_;
};
template<typename Ind>
class Process {
public:
static const size_t size = size_helper<Ind>::size;
Process() = default;
std::array<OtherType, Ind::size_> individuals;
};
The easiest way is to add a static variable.
template<size_t SIZE>
class Individual{
public:
static constexpr auto size = SIZE;
std::bitset<SIZE> data;
};
template<typename Ind>
class Process {
public:
Process() = default;
std::array<OtherType, Ind::size> individuals;
};

Templated Automatic Factory Registration

Imagine I had some objects that were all related to some interface class base. However, all of these objects are templated by some integer DIM (dimension). I have assumed all derivatives of base have a static member int number() and a static string InputName. The idea is to register this static method number(). (Really each class will have whole static interface.)
Registration.hpp
template <int DIM>
class objectRegistry
{
public:
template<typename T>
Register()
{
//something like interface_map[T::InputName] = T::number;
}
private:
static inline std::map<std::string, std::function<int ()>> interface_map;
}
Header1.hpp
template <int DIM>
class base
{
public:
static inline const std::string InputName = "base";
static int number() { return 1; };
base(){};
};
//todo: Some Registration Here
Header2.hpp
template <int DIM>
class derived : public base<DIM>, public AutomaticRegister<DIM, derived<DIM>>
{
public:
static inline std::string InputName = "derived";
static int number() { return 4; };
derived(){};
};
//todo: Some Registration Here
hearder3.hpp
template <int DIM, typename extra_type>
class derived2 : public base<DIM>, public AutomaticRegister<DIM, derived2<DIM,extra_type>>
{
public:
static inline std::string InputName = "derived2 " + std::string(typeid(extra_type).name());
static int number() { return 5; };
extra_type member;
};
//todo: Some Registration Here
Can I create an automatic registration system for derived objects (all derived from base); ideally, one that exists in the same header file as the object definition. I would like, for example, objectRegistry<3> to know that derived<3>, derived2<3,int>, and derived<3,double> exist. I have tried these methods:
Best way to for C++ types to self register in a list?
https://www.bfilipek.com/2018/02/factory-selfregister.html
However, because everything is buried in the template< int DIM>, it is never instantiated.
Is there a way I can force derived to instantiated when objectRegistry is instantiated with a particular template value?
Either of the two approaches you linked to will work.
Your problem is that you are using class templates, not classes.
If you did this
class Something : public AutomaticRegister<Something>
{
// ...
};
then you would get automatic registry, because Something is a class.
You have class templates, which are not anything like a type at all.
The registration happens by instantiating the registration class, which is a base class of your class template.
So, in order to instantiate the registration class, you need the stuff you want registered to be treated as a type. Thus, you need to instantiate some part of the class, either by creating an instance of one of the templates...
derived2<1, double> d2_1_double;
or by explicitly instantiating the entire class template...
template class derived2<1, double>;
or by explicitly instantiating some member of the class template, like the number function...
template int derived2<1, double>::number();
or by creating an actual derived class...
struct d2_1_double : derived2<1, double> { };
or some other way to stamp out a class from a class template.
However, a very minor change to the registration class template (adding a type member alias) gives us a mechanism to register them explicitly in bulk, and does not require inheriting from the registration mechanism.
To demonstrate, I added a bit of extremely simple non-production-quality code. To do so, I added a non-standard function to get a unique name for a type that will work for gcc and clang, but no idea about other compilers. It is not necessary, just makes it easier for me.
#include <functional>
#include <iostream>
#include <string_view>
#include <unordered_map>
template <typename ... Ts> struct TypeList { };
template <typename T>
constexpr auto
fname()
{
return __PRETTY_FUNCTION__;
}
class Registry
{
std::unordered_map<std::string_view, std::function<int()>> map;
public:
void insert(std::string_view key, std::function<int()> value) {
assert(map.find(key) == map.end());
std::cout << "Register \"" << key << "\", " << value() << '\n';
map[key] = std::move(value);
}
int operator()(std::string_view key) const {
return map.at(key)();
}
};
template <int DIM>
Registry & registry()
{
static Registry result;
return result;
}
And here is the stuff to do the auto-registration, a modified version of the answer from one of your links.
template <typename T>
class AutoRegister
{
struct helper {
helper() { registry<T::dim>().insert(fname<T>(), T::number); }
};
/* inline */ static helper h;
template<helper&> struct ref { using type = AutoRegister; };
public:
using type = typename ref<h>::type;
};
// NOTE: A bug in gcc forces this usage rather than just using inline.
template <typename T>
typename AutoRegister<T>::helper AutoRegister<T>::h;
Then, with some class templates similar to yours...
template <int DIM>
struct Bar
{
static constexpr int dim = DIM;
static int number() { return dim*100 + 99; }
};
template <int DIM, typename T>
struct Baz
{
static constexpr int dim = DIM;
static int number() { return dim*100 + 86; }
};
template <int DIM, typename ... Ts>
struct Foo
{
static constexpr int dim = DIM;
static int number() { return dim*100 + 42; }
};
and a helper alias template...
template <typename ... Ts>
using RegisterTypes = TypeList<typename AutoRegister<Ts>::type...>;
We can register the stuff we want. The second one has some duplicates just to show that stuff gets registered once.
using Registered = RegisterTypes<Bar<0>, Bar<1>, Baz<1>, Foo<1>>;
using Registered2 = RegisterTypes<Bar<2>, Bar<1>, Baz<1>, Foo<1>>;
int main()
{
}
Running the program results in the following output...
Register "auto fname() [T = Bar<0>]", 99
Register "auto fname() [T = Bar<1>]", 199
Register "auto fname() [T = Baz<1, int>]", 186
Register "auto fname() [T = Foo<1, int>]", 142
Register "auto fname() [T = Bar<2>]", 299
Register "auto fname() [T = Foo<1, int, double>]", 142```

How to get the value of a non-type template parameter?

Here is the example:
template <int n>
class A { };
class B {
public:
int foo() {
return a.n; // error
}
private:
A<10> a;
};
I want to get the value of instantiated class A<10>'s non-type template parameter in class B other than template A itself, is there a way to do this? Or should I use some other designs to avoid this problem?
You can't access other classes template parameters just like that. The other class has to expose it, for instance:
template <int n>
class A {
public:
static const int num = n;
};
Then you can access it as a.num (or A<10>::num of course)
If you can't get the type to cooperate (by publishing the parameter value), you can extract it yourself with a traits class:
template<class> struct A_param; // not defined
template<int N> struct A_param<A<N>> {
static constexpr int value = N;
};
// a more general implementation would probably want to handle cv-qualified As etc.
Then use A_param<decltype(a)>::value.
If you have a member A<10> your class B already know about the template parameter. Use that value instead. If the template parameter is indeed not named, let A define a member that reflects the template parameter.
1 -
class B {
public:
int foo() {
return n;
}
private:
const int n = 10;
A<n> a;
};
2 -
template <int n>
class A {
public:
static const int template_param = n;
};

CRTP + Traits class : "no type named..."

I try to implement a CRTP with templated class and I have an error with the following example code :
#include <iostream>
template<class T> class Traits
{
public:
typedef typename T::type type; // <- Error
// : "no type named 'type' in 'class MyClass<double, 3u, 3u>'
static const unsigned int m_const = T::m_const;
static const unsigned int n_const = T::n_const;
static const unsigned int size_const = T::m_const*T::n_const;
};
template<class T0> class Crtp
{
public:
typedef typename Traits<T0>::type crtp_type;
static const unsigned int size = Traits<T0>::size_const; // <- This is OK
};
template<typename TYPE, unsigned int M, unsigned int N>
class MyClass : public Crtp< MyClass<TYPE, M, N> >
{
public:
typedef TYPE type;
static const unsigned int m_const = M;
static const unsigned int n_const = N;
};
int main()
{
MyClass<double, 3, 3> x;
std::cout<<x.size<<std::endl;
return 0;
}
I do not understand what causes this problem nor how to fix it.
In fact my goal is that the CRTP class have to know the template arguments of the derived class WITHOUT passing them as template argument of the CRTP class.
Do you have any ideas how to implement this?
EDIT (relating to the first first) : My CRTP class has to be able to handle derived classes with different number of template parameters
The problem is that MyClass is incomplete in its own base class list, where you instantiate Crtp<MyClass>. But instantiating Crtp<MyClass<...>> requires instantiating Traits<MyClass<...>> which then requires instantiating MyClass<...>::type which is impossible because it's incomplete. You have a circular dependency.
In fact my goal is that the CRTP class have to know the template arguments of the derived class
That can be done using a partial specialzation and a template-template-parameter, like so:
#include <iostream>
template<typename T> class Crtp;
template<template<typename, unsigned, unsigned> class T, typename U, unsigned M, unsigned N>
class Crtp< T<U, M, N> >
{
public:
typedef U crtp_type;
static const unsigned int size = M * N;
};
template<typename TYPE, unsigned int M, unsigned int N>
class MyClass : public Crtp< MyClass<TYPE, M, N> >
{
};
int main()
{
MyClass<double, 3, 3> x;
std::cout<<x.size<<std::endl;
return 0;
}