Static polymorphism with constant template - c++

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;
}

Related

Virtual method with unspecialized template argument

#include <iostream>
#include <array>
#include <vector>
using namespace std;
// Currently I have code much like this one:
template <const uint32_t N>
using VectorN = array<double, N>;
template <const uint32_t N>
class ITransformable {
public:
virtual vector<VectorN<N>>& positions() = 0;
};
class SomeTransformer {
public:
template <const uint32_t N>
void operator()(ITransformable<N>& transformable) const {
/* implementation */
}
};
// Then I want to create interface like this.
template <const uint32_t N>
class ITransformer {
public:
virtual void operator()(ITransformable<N>& transformable) const = 0;
};
// And finally implement it for SomeTransformer:
//
// Notice that class is not template, this is intentional.
//
// class SomeTransformer : public ITransformer<N> {
// public:
// virtual void operator()(ITransformable<N>& transformable) const {
// /* implementation */
// }
// }
Actually, now it seems impossible to me. Otherwise this class would inherit
indefinite number of interface specializations...
But still, is it possible, at least for finite number of dimensions N?
template <template <typename> class C> seems to be related, but I can't figure out how to apply this.
EDIT
What I want is something like this:
class SomeTransformer :
public ITransformer<2>,
public ITransformer<3>,
public ITransformer<4>,
...,
public ITransformer<N> {
/* ... */
};
For any N ever used in code. This seems impossible, as I said.
You can achieve what you want or nearly that. Here's what I propose:
#include <type_traits>
#include <utility>
template<std::size_t N>
struct ITransformer {};
template<class T>
class SomeTransformer_h { };
template<std::size_t... Indices>
class SomeTransformer_h<
std::integer_sequence<std::size_t, Indices...>> :
public ITransformer<1 + Indices>... { };
template<std::size_t N>
class SomeTransformer : public SomeTransformer_h<
std::make_index_sequence<N>
> { };
int main() {
SomeTransformer<5> a;
ITransformer<1>& ref = a;
ITransformer<4>& ref2 = a;
ITransformer<5>& ref3 = a;
}
Now for any N it will make SomeTransformer inherit all ITransformer from 1 to N.
Since N is not declared anywhere, you cannot use it. You need something like:
class SomeTransformer : public ITransformer<5> {
public:
virtual void operator()(ITransformable<5>& transformable) const {
/* implementation */
}
};
or make it a template class:
template <uint32_t N>
class SomeTransformer : public ITransformer<N> {
public:
virtual void operator()(ITransformable<N>& transformable) const {
/* implementation */
}
};
UPDATE
There is no dynamic inheritance in C++. Therefore, what you want to achieve is not possible.

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 specialize a non-templated-member function of a template class for multiple types?

I'm biting of my nails on the syntax required to partially specialize a member function for multiple types. Here is what I have:
#include <cstdint>
#include <string>
class Property
{
public:
virtual int read(uint8_t *) = 0;
};
template<typename T>
class PropertyValue
{
T value_;
public:
int read(uint8_t *);
};
// specialized for std::string
template<>
int PropertyValue<std::string>::read(uint8_t *buf) { /* put string-value to buf */}
Now I would want to specialize the read-function for different enum-types. I tried a combination of enable_if and is_same which looks promissing, then putting it inside the template-declaration (compiler told me there are now 2 template arguments whereas 1 was expected).
Putting it inside the class-definition was not working either. Outside ... well, here's what I currently have.
// specialize for some enums
template<typename T>
typename std::enable_if<std::is_same<T, enum Enum1>::value ||
std::is_same<T, enum Enum2>::value, int>::type
PropertyValue<T>::read(uint8_t *buf)
{
return encode_enum(buf, value_);
}
Where is my thinking wrong?
EDIT: Writing it like this compiles and works:
template<>
int PropertyValue<Enum 1>::read(uint8_t *buf)
{
return encode_enum(buf, value_);
}
template<>
int PropertyValue<Enum 2>::read(uint8_t *buf)
{
return encode_enum(buf, value_);
}
PropertyValue::value itself is not a template. It's not a template class, it's not a template function. It's a member of a template class, which is not the same thing as being a template itself.
You have to specialize the entire class.
template<>
class PropertyValue<std::string>
{
std::string value_;
public:
int read(uint8_t *)
{
// Your specialization goes here.
}
};
Even if read() itself was a template, you must still specialize its class, before you can specialize a template class's template member.
Of course, if your template class has many other members and methods, every one of them have to be specialized here, leading to plenty of code getting duplicated. At that point, you will be faced with several options for refactoring out that duplicated code. The best approach for that depends on the particular details.
But that's how it's done...
EDIT: one common approach is to use a helper template class:
template<typename T> class PropertyValue; // Forward declaration
template<typename T> class do_read {
public:
static int do_it( PropertyValue<T> &me, uint8_t *p )
{
// your default implementation
}
};
template<> class do_read<std::string> {
public:
static int do_it( PropertyValue<std::string> &me, uint8_t *p )
{
// your specialization
}
};
template<typename T>
class PropertyValue
{
T value_;
public:
int read(uint8_t *p)
{
return do_read<T>::do_it(*this, p);
}
};

Partial specializations of templatized alias declarations

In this question I am led to a particular solution which involves partial specializations of templatized alias declarations. The generic case is described in this answer. Suppose I have a template class
template<typename T, ...>
class X {
// ....
};
Rather than leaving T free and specializing the other template parameters I am in a situation in which the other arguments depend on T, and on T alone. As a very concrete example (more manageable than the example in the other question) consider a template class
template<typename T, T absVal(T)>
class Number_impl {
private:
T _t;
public:
Number_impl(T t): _t(t) {}
T abs() const {return absVal(_t);}
};
Possible specializations are
Number_impl<int, std::abs>;
and
Number_impl<double, std::fabs>;
(I know there are overloaded abs versions, this is just for the sake of illustration. See my other example if you want).
Ideally I would like to define a template class Number depending on a single argument, the type, so that Number<int> is equal to
Number_impl<int, std::abs>;
and Number<double> is equal to
Number_impl<double, std::fabs>;
Something like the following (which doesn't work):
template<typename T>
using Number = Number_impl<T, nullptr>;
template<>
using Number<int> = Number_impl<int, std::abs>;
template<>
using Number<double> = Number_impl<double, std::fabs>;
Does anyone know if and how this can be made to work, or how the same can be achieved in a different way?
The normal way to do this kind of thing is the same way the standard library does it - with a traits class that you can specialise:
#include <iostream>
#include <cmath>
template<typename T> struct NumberTraits;
template<typename T, class Traits = NumberTraits<T>>
class Number {
private:
T _t;
public:
Number(T t): _t(t) {}
T abs() const {
return Traits::abs(_t);
}
};
template<> struct NumberTraits<int>
{
static int abs(int i) {
return std::abs(i);
}
};
template<> struct NumberTraits<double>
{
static double abs(double i) {
return std::fabs(i);
}
};
using namespace std;
auto main() -> int
{
Number<int> a(-6);
Number<double> b(-8.4);
cout << a.abs() << ", " << b.abs() << endl;
return 0;
}
expected output:
6, 8.4
You may add a layer:
template<typename T, T absVal(T)>
class Number_impl {
private:
T _t;
public:
Number_impl(T t): _t(t) {}
T abs() const {return absVal(_t);}
};
template<typename T> struct Number_helper;
template<> struct Number_helper<int> { using type = Number_impl<int, std::abs>; };
template<> struct Number_helper<double> { using type = Number_impl<double, std::fabs>; };
template<typename T>
using Number = typename Number_helper<T>::type;

Accessing nested template parameters without template template arguments

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; };