Considering the following two usage scenarios (exactly as you see them, that is, the end-user will only be interested in using Vector2_t and Vector3_t):
[1]Inheritance:
template<typename T, size_t N> struct VectorBase
{
};
template<typename T> struct Vector2 : VectorBase<T, 2>
{
};
template<typename T> struct Vector3 : VectorBase<T, 3>
{
};
typedef Vector2<float> Vector2_t;
typedef Vector3<float> Vector3_t;
[2]Specialization:
template<typename T, size_t N> struct Vector
{
};
template<typename T> struct Vector<T, 2>
{
};
template<typename T> struct Vector<T, 3>
{
};
typedef Vector<float, 2> Vector2_t;
typedef Vector<float, 3> Vector3_t;
I can't make up my mind as to which is a nicer solution.
The obvious advantage to inheritance is code reuse in the derived classes; a possible disadvantage being performance (bigger size, users may pass by value, etc).
Specialization seems to avoid all that, but at the expense of me having to repeat myself multiple times.
What other advantages/disadvantages did I miss, and in your opinion, which route should I take?
What you ultimately want, i think, is to have the user type
Vector<T, N>
And depending on N, the user will get slight different things. The first will not fulfill that, but the second will, on the price of code duplication.
What you can do is to invert the inheritance:
template<typename T, size_t N> struct VectorBase
{
};
template<typename T> struct VectorBase<T, 2>
{
};
template<typename T> struct VectorBase<T, 3>
{
};
template<typename T, size_t N> struct Vector : VectorBase<T, N>
{
};
And implement the few functions that depend only on N being some specific value in the appropriate base-class. You may add a protected destructor into them, to prevent users deleting instances of Vector through pointers to VectorBase (normally they should not even be able to name VectorBase: Put those bases in some implementation namespace, like detail).
Another idea is to combine this solution with the one mentioned in another answer. Inherit privately (instead of publicly as above) and add wrapper functions into the derived class that call the implementations of the base-class.
Yet another idea is to use just one class and then enable_if (using boost::enable_if) to enable or disable them for particular values of N, or use a int-to-type transformer like this which is much simplier
struct anyi { };
template<size_t N> struct i2t : anyi { };
template<typename T, size_t N> struct Vector
{
// forward to the "real" function
void some_special_function() { some_special_function(i2t<N>()); }
private:
// case for N == 2
void some_special_function(i2t<2>) {
...
}
// case for N == 3
void some_special_function(i2t<3>) {
...
}
// general case
void some_special_function(anyi) {
...
}
};
That way, it is completely transparent to the user of Vector. It also won't add any space overhead for compilers doing the empty base class optimization (quite common).
Use inheritance and private inheritance. And don't use any virtual functions. Since with private inheritance, you don't have is-a, no one will be able to use a baseclas pointer to a derived subclass, and you won't get the slicing problem when passinfg by value.
This gives you the best of both worlds (and indeed it's how most libraries implement many of the STL classes).
From http://www.hackcraft.net/cpp/templateInheritance/ (discussing std::vector, not your Vector class):
vector<T*> is declared to have a
private base of vector<void*>.
All functions which place a new element
into the vector, such as push_back(), call the
equivalent function on this private base,
so internally our vector<T*> is using a
vector<void*> for storage. All functions
which return an element from the vector, such as
front(), perform a static_cast on the
result of calling the equivalent function
on the private base. Since the only way to get a
pointer into the vector<void*> (apart from
deliberately dangerous tricks) is through the
interface offered by vector<T*> it is safe
to staticly cast the void* back to T*
(or the void*& back to T*&, and so on).
In general, if the STL does it like this, it seems like a decent model to emulate.
Inheritance should only be used to model "is-a". Specialization would be the cleaner alternative. If you need or want to use inheritance for whatever reason, at the very least make it private or protected inheritance, so you don't inherit publicly from a class with a public non-virtual destructor.
Yes, the template metaprogramming guys always do
struct something : something_else {};
But those somethings are metafunctions and not meant to be used as types.
You need to decide the 'correct' answer to the following questions, based on your actual use case and what the real public interface should be:
Is "Vector<T,N>" your main public interface or an implementation detail? As in, are people supposed to use these objects like std::vector or is it simply a way to hide common implementation logic for the real API of "vector_2", etc.?
Will all "Vector<T,N>" have the same logical behavior? Most people will tell you to follow the STL when it comes to these types of decisions, but the STL itself infamously screwed this up with std::vector<bool>. And they've been forced to support the resulting mess for 30 years.
One thing to bear in mind is that you can combine both inheritance and template specialization; they're not mutually exclusive. And template specializations should be transparent to users, meaning they should have the same public interface and behavior as the general template.
For example:
template <typename T, size_t N>
class VectorBase {
public:
// The public interface all 'vector-like' classes must honor
virtual T& at(size_t index) = 0;
// More APIs...
};
// The generic Vector<T,N>
// Let's forbid inheritance from vectors, for now.
template <typename T, size_t N>
class Vector final : public VectorBase<T, N>
{
public:
// Have to implement the public interface
virtual T& at(size_t index) override;
// Vector-only APIs
virtual T* data();
};
// We've got some optimized way of storing, let's say doubles, that doesn't fit the general case
template <size_t N>
class Vector<double, N> final : public VectorBase<double, N>
{
public:
// Same APIs as baseline Vector<T,N>
virtual double& at(size_t index) override;
};
// We DISABLE a specialization, e.g. Vector<bool, N>
template <size_t N>
class Vector<bool, N> final : public VectorBase<bool, N>
{
}; // Nobody can ever create one of these. We never implemented the pure virtual APIs and we disabled inheritance.
// A different object that has a lot of interface overlap with Vector<T, N>
template <size_t N>
class Bitset : public Vector<bool, N>
{
public:
// From VectorBase
virtual bool& at(size_t index) override;
// Unique to me
virtual void bitwise_not();
virtual void bitwise_or(const Bitset<N>& other);
//...
};
To share code between the generic "Vector<T,N>" and its specializations, you have several options. The most straightforward way is the put it in protected functions of the base class.
If you're using template specialization too much, you probably need to rethink your design. Considering that you're hiding it behind a typedef, I doubt you need it.
Related
Recently I was asked a question. I have the below templated class:
template<size_t SIZE>
class Cache
{
// A lot of class methods omitted
std::array<int, SIZE> _arr;
};
but someone might pass large a size and allocate on the stack, running out of stack memory. So you might suggest changing it to allocate on the heap:
template<size_t SIZE>
class Cache
{
// A lot of class methods omitted
std::unique_ptr<std::array<int, SIZE>> _arr;
};
but now those wanting a small array will pay the cost of indirection (i'm aware this is a very small cost but for the point of the question please accept).
Consequently it was hinted to me template specialization can allow some to choose the small std::array implementation and others to allocate their array on the heap.
I presume this specialization must be at the class level, because the std::array is a class member.
How is this class template specialization achieved without duplicating all the (omitted) class methods?
How is this class template specialization achieved without duplicating all the (omitted) class methods?
Abstract the thing you care about away into its own mixin class. For example:
template<size_t SIZE, bool> // default case, condition is false
class storage {
std::unique_ptr<std::array<int, SIZE>> _arr;
protected:
// constructor too...
std::array<int, SIZE>& arr() { return *_arr; }
};
template<size_t SIZE> // special case, condition is true
class storage<SIZE, true> {
std::array<int, SIZE> _arr;
protected:
// constructor too...
std::array<int, SIZE>& arr() { return _arr; }
};
Then simply have the cache use it as base, while checking SIZE for a threshold:
template<size_t SIZE>
class Cache : private storage<SIZE, (SIZE < THRESHOLD)>
{
// A lot of class methods omitted
// They now use this->arr();
};
You may also opt for composition instead. The specialization is pretty much the same in this case, but arr() is gonna need to be public so Cache may access it.
I have 6 types of datastructure<T>.
All of them contains cover 10-20 common functions (purple) e.g. addFirst().
However, some datastructures has its own 0-5 unique functions (pink).
For example, only MyArray<T> has function addManual(T,int).
In rare cases, some different types of datastructure support a few same special function.
(The real-case table is ~ 10x more complex.)
Here is a short snippet :-
class Vector3D{};
template<class T>class MyArray{
public: void addFirst(T t){/* some code */}
/* other add / remove / query function */
public: void addManual(T t,int internalIndex){/* some code */}
};
template<class T>class MyGrid3D{
public: void addFirst(T t){/*some code */}
/* other add / remove / query function */
public: void addSpecial(T t,Vector3D gridAddress){/* some code*/}
};
It works good so far.
Now, I want to make it usage easier by providing interface Adapter<MyX,T,I>.
The user of my library can identify the internal stored type T and the interface I separately.
Whenever a parameter of function (purple/pink) has type I, I will convert it to T and internally manipulate it as if it has type T.
Here is my prototype :-
template<template<class> class MyX,class T,class I>class Adapter{
private: T convert(I i){/* some logic */ return T();}
MyX<T> database;
public: void addFirst(I i){
database.addFirst(convert(i));
}
};
int main() {
Adapter<MyArray,int,std::string> adapter;
adapter.addFirst(std::string("5.0f"));
std::cout<<"compiled OK";
return 0;
}
It works good (coliru demo), but it doesn't cover special function (purple) e.g. addManual() or addSpecial() .
Question
What is a design pattern / C++ magic to make Adapter support those functions?
Here are my three poor solutions :-
Create many adapter class for each type of datastructure, e.g. AdapterMyArray<T,I> and AdapterMyGrid3D<T,I>.
Improve the first solution by inheritance e.g. AdapterMyArray<T,I> and AdapterMyGrid3D<T,I> derived from AdapterBase<T,I>.
Check type of MyX and use std::enable_if to enable instantiate of those special functions.
I feel that all my solutions are somehow too manual and it will cause some maintainability issue.
Edit: Yakk's solution is good, but I still doubt if there are even better solution.
CRTP.
Have Adapter_addFirst Adapter_addManual etc CRTP helpers. They use CRTP to access database<T> and implement their one (or set of) functions.
Adapter queries database or database<T> via traits class helpers to determine which of the CRTP Adapter_*s it should inherit (publicly) from.
template<class D, class I>
class Adapter_addFirst {
D* self() { return static_cast<D*>(this); }
D const* self() const { return static_cast<D*>(this); }
public:
void addFirst(I i){
self()->database.addFirst(self()->convert(i));
}
};
template<std::size_t I>
struct empty_t {};
template<template<class> class MyX,class T,class I>
class Adapter:
public std::conditional_t<true, Adapter_addFirst<Adapter<MyX, T, I>, I>, empty_t<0>>
{
friend struct Adapter_addFirst<Adapter<MyX, T, I>, I>;
private:
T convert(I i){/* some logic */ return T();}
MyX<T> database;
};
where true is replaced with a test of "should I have addFirst".
Repeat for each of the methods.
Dispatch is static, methods only exist if they should, everything is standard compliant.
You can test for "should I addManual" either via tags on your types, type traits, or even SFINAE test of a call to std::declval<MyX<T>&>().addManual( std::declval<T const&>() ). For the SFINAE case, see can_apply or equivalent.
I have a class with M number of methods, and only one method performs read-only operations on a std::array. The rest of the M-1 methods do not use the std::array. Code below. Assume I can't break up this class.
My concerns are:
This code is little ugly because, as mentioned, only 1 method uses the parameter N.
If I instantiate Bar 100 times each with different N's, then doesn't that bloat the code? Like I said, only 1 method uses the parameter N, yet my understanding is that I'll get 99*(M-1) extra copies of effectively the same method.
That being said, is it standard to use a vector or a C-array instead to avoid template? Will I be sacrificing any potential performance?
//bar.h
template<int N>
class Bar
{
public:
Bar(const std::array<Foo, N>& arr);
void method_one();
void method_two();
void method_three();
...
private:
const std::array<Foo, N> arr_;
};
template<int N> Bar<N>::Bar(const std::array<Foo, N>& arr) :
arr_(arr)
{}
template<int N> void Bar<N>::method_one()
{
//....
}
template<int N> void Bar<N>::method_two()
{
//....
}
//etc
First, your compiler might (or might be induced to) fold identical functions even if they have different signatures.
Whether that is legal (and how to force it), see here:
Do distinct functions have distinct addresses?
Is an implementation allowed to site two identical function definitions at the same address, or not?
Next, if members of your template are independent of template-arguments, consider moving them to a base-class:
class Bar_base {
// Move everything here not dependent on template-arguments.
// Can be done multiple times if useful
}
template<int N> class Bar : public Bar_base {
// Everything dependent on `N`, and maybe some using-declarations
// for proper overloading
}
All implementations of the standard library do it extensively, and if you look at <iostream>, it's even codified in the standard.
If only the constructor uses std::array<...,N> you may turn your templated class into a standard class with templated constructor. Further more I would hope that the compiler is clever enough to not copy 100s of code fragment that do not have any dependency on N.
class Bar
{
public:
template<int N>
Bar(const std::array<Foo, N>& arr);
...
...
}
EDIT: Crap !! This doesn't seem to compile... It works with parameters like
class Bar {
public:
template<int N>
Bar(const int (& a)[N]);
I have some code that compiles and works fine in C++ (as long as I forward declare the generic template class, then the specialized instance, and then define the generic template class - see inheriting from class of specialized self?). When I try to use SWIG to add C# bindings to the class, however, it either crashes SWIG or doesn't include the methods from the inherited class. I believe this is only possible in C++11, but I'm not sure as I haven't tried this with an older compiler.
Here's a toy example:
template <typename T, int N = 0> class A;
template <typename T> class A<T, 0>
{
public:
A() : mFoo(NULL) {}
virtual ~A() {}
T* getFoo() { return mFoo; }
protected:
T* mFoo;
};
template <typename T, int N = 0> class A : public A<T, 0>
{
public:
A() : A<T, 0>(), mBar(N) {}
virtual ~A() {}
int getBar() const { return mBar; }
protected:
int mBar;
};
In a program, I can then instantiate an instance of A<char,10> (for example), and have access to mFoo and mBar, or just instantiate an instance of A and only have access to mFoo. I can also use methods with parameters like
void baz(A<T, 0>* anyA)
and the method will accept A<T, 0> or A<T, n> instances.
For context and explanation, this pattern works well for containers that can be either dynamic or fixed size. If they are dynamic, you can just instantiate it as a A<T, 0> and not have the overhead of inheritance, etc. or you can have a fixed-sized container (A<T, N> where N > 0) that does use inheritance, but has access to all the "base" class methods, can override them as needed, and still be accepted as a parameter for methods that accept either dynamic or fixed-sized instances of the container.
However, when I try to use SWIG so that I can use this class in other languages, I run into issues.
At first, I tried something like:
%template(tA) A<char, 0>;
but this causes SWIG to crash (at least in version 3.0.0 that I'm currently using).
Next, thinking that, like all template inheritance in SWIG, I need to have an existing template for the base class as well as the inheritor class (if both are templated anyway). So I tried
%template(tABase) A<char, 0>;
%template(tA) A<char>;
This also causes SWIG to crash.
So, I tried to be a little clever and take advantage of SWIGS ability to use a "nameless" template for classes that are inherited from and did something like:
%template() A<char, 0>;
%template(tA) A<char>;
This avoids the crash and I get an output of the tA class, but it only has the methods, etc. from the inheritor class A<T, N> and does not actually inherit from the A<char, 0> specialized template instance that it needs to and thus I have no access to all the methods and data in the "base" class of A<char, 0>.
Has anyone else tried to get SWIG to handle this? Successfully? Is there a command line param that I can pass to SWIG that will make things work (and stop it from crashing)?
The easiest way I can see to solve your problem is to stop being so fancy that you confuse the other languages, by being fancier within C++:
template<typename T>
struct A0_impl;
template<typename T, typename N>
struct A_impl;
template<typename T, int N>
struct A_helper {
typedef A_impl<T,N> type;
};
template<typename T>
struct A_helper<T,0> {
typedef A0_impl<T> type;
};
template<typename T, int N=0>
using A = typename A_helper<T,N>::type;
template<typename T>
struct A0_impl {
A0_impl() : mFoo(nullptr) {}
virtual ~A0_impl() {}
T* getFoo() { return mFoo; }
private:
T* mFoo;
};
template<typename T, typename N>
struct A_impl:A0_impl<T> {
A_impl() : A0_impl<T>(), mBar(N) {}
virtual ~A_impl() {}
int getBar() const { return mBar; }
protected:
int mBar;
};
template<typename T>
struct A_impl<T,0>:A0_impl<T> {
A_impl() : A0_impl<T>() {}
virtual ~A_impl() {}
// possibly inherit other constructors from A0_impl
};
this gives you C++ code that behaves nearly exactly like your version, but does away with that descend-from-specialization issue that you believe is causing your problems.
Basically I replaced your A<T,0> specialization with A0_impl, and the template alias A<T,N> now maps to either A_impl<T,N> or A0_impl<T> depending on if N is 0 or not.
The A template alias is optional, as you could instead have A0_impl be called AnySizedA and A_impl be called FixedSizeA, and instead of specializing A<T,0> to do something simply ban it.
I recently saw some code using macros like
#define CONTAINS(Class, Name)\
private:\
std::list<Class> m_##Name##s;\
public:\
void add_##Name(const Class& a_##Name) {\
m_##Name##s.push_back(a_##Name);\
}\
int get_##Name(int pos) {\
return m_##Name##s.at(pos);\
}\
// ... more member functions
Later you can declare a class like
class my_class {
CONTAINS(int, integer)
// ...
};
and write
my_class a(...);
a.add_integer(10);
I was puzzled about this paste-in-macro-style because I'm missing concrete counter-arguments. But beside that I accept the following pros
you can easily add a list interface for arbitrary types to your class
you avoid frequently repeated code
you have an easy to use interface (like add_integer(10))
Now I'm searching for alternatives which meet all these points above and avoid this old C macro style. My first idea was to create an abstract base class template
template<typename T>
class list_interface {
private:
std::list<T> m_list;
public:
void add_element(const T& x) {
m_list.push_back(x);
}
// ... more member functions
};
and add it to my class via inheritance like this
class my_class : public list_interface<int> {
// ...
};
Now I can write too
my_class a;
a.add_element(10);
but I'm concerned about the following points:
you can only add one list to your class
you publicly inherit from a class without virtual destructor
I don't meet the third point of the pros (add_element(10) instead of add_integer(10))
My questions are:
What are the drawbacks of the old C macro construct
How can I provide a similar functionality without macros
How about:
#include <vector>
template<typename T>
class Plop
{
std::vector<T> data;
public:
void add(T const& v) {data.push_back(v);}
T get(int pos) {return data.at(pos);} // at() is not valid on lists.
};
class my_class
{
public:
Plop<int> integer;
Plop<float> floater;
};
int main()
{
my_class x;
x.integer.add(5); // similar to x.add_integer(5);
x.integer.get(0); // similar to x.get_integer(0);
}
It meets all the requirements:
you can easily add a list interface for arbitrary types to your class
you avoid frequently repeated code
you have an easy to use interface (like add_integer(10))
My questions are:
What are the drawbacks of the old C macro construct
The ick factor.
Debugging.
Can pass individual list to other functions or methods.
How can I provide a similar functionality without macros
See above.
my opinion
1) Yuck yuck. Complex macro which will hinder debugging. Just the view of the macro makes my skin crawl.
2) Your inheritance solution looks fine. If you really needed multiple lists of different types, you might want to consider just writing more code and instantiating the list as a member variable. There really is no benefit of attempting to reduce lines of code by making it convoluted.
There is a way, in meta-programming fashion, and using tags.
First, let's consider the roll your own solution.
The idea is to come up with this interface:
class my_class : public vector<Name, std::string>, public vector<Foo, int>
{
};
And then, to use it like this:
my_class a;
a.add<Name>("Peter");
a.add<Foo>(3);
Now, lets dive behind the covers. We are going to use SFINAE combined with enable_if.
template <class Tag, class Type>
class vector
{
template <class T, Return>
struct Enable
{
typedef typename boost::enable_if<
boost::is_same<T,Tag>,
Return
>::type type;
}; // Enable
public:
template <class T>
typename Enable<T,void>::type
add(Type const& i) { m_elements.push_back(i); }
template <class T>
typename Enable<T, Type const&>::type
get(size_t i) const { return m_elements.at(i); }
// You'd better declare a whole lot of other methods if you really want that
// like empty, size and clear at the very least.
// Just use the same construct for the return type.
protected:
vector() : m_elements() {}
vector(vector const& rhs) : m_elements(rhs.m_elements) {}
vector& operator=(vector const& rhs) { m_elements = rhs.m_elements; return *this; }
~vector() {} // Not virtual, because cannot be invoked publicly :)
private:
std::vector<Type> m_elements; // at() is inefficient on lists
};
How does this work ?
Basically when you invoke get<Name> the compiler has 2 alternatives:
vector<Name,std::string>::get
vector<Foo,int>::get
Now, thanks to enable_if, the second alternative is ill-formed (the type deduced cannot be used because Foo != Name), and thus, thanks to SFINAE, this alternative is removed from the list without any complaint.
Then, since there is only one alternative, it gets selected. And of course, since this is done at compile-time, you don't actually have any runtime penalty.
If you want to skip some work (for this type). You could also simply use a simpler construct:
template <class Tag, class Embedded>
class Embed
{
// redeclares same private and protected interface
public:
template <class T>
typename Enable<T,Embedded &>::type get() { return m_element; }
template <class T>
typename Enable<T,Embedded const&>::type get() const { return m_element; }
private:
Embedded m_element;
};
Then you use it like so:
class my_class: public Embed< Names, std::vector<std::string> >,
public Embed<Foo,int>
{
};
my_class a;
std::vector<std::string> const& names = a.get<Names>();
int foo = a.get<Foo>();
a.get<Names>().push_back("Peter");
It's easier since you only provide accessors and don't have to write a whole bunch of methods just to forward the work.
And now that we've work so much, we should ask ourselves: this seems quite practical and generic, surely there is a library or something ?
There is >> Boost.Fusion's map:
class my_class
{
public:
template <class Tag>
typename result_of::at_key<map_type, T>::type &
get() { return at_key<T>(m_data); }
template <class Tag>
typename result_of::at_key<map_type, T>::type const&
get() const { return at_key<T>(m_data); }
private:
// First element of the pair: TAG
// Second element of the pair: Actual type of the data
typedef boost::fusion::map <
std::pair<Name, std::vector<std::string> >,
std::pair<Foo, int>
> map_type;
map_type m_data;
};
The main issue with the macro is: it is solving a problem you don't really have.
It is making a class with list members, where the lists are manipulated directly.
Because we think in OO, members should be encapsulated and we want to use DRY, we come to this construct, while my_class remains really a data-class.
If all the class has to do is contain lists, turn it into a struct and keep the lists public.
This way you have a clean intention and the lists can be accessed the STL-way.
If the class needs to have control over the lists, then you shouldn't expose the lists and the macro's are of little use.
So my code would be (not compiled):
struct my_class {
std::list<int> integers;
std::list<std::string> names;
// ...
};
int main()
{
my_class lists;
lists.integers.push_back(5);
size_t size_names = lists.names.size();
}
Pro:
easily add lists
no code duplication
consistent (STL) interface
straightforward
no macro's
Con:
no data encapsulation, if that would be a requirement
For multiple lists, you can try multiple inheritance with typedefs. Something like:
class my_class : public list_interface<int>, public list_interface<float> {
public:
typedef list_interface<int> Ints;
typedef list_interface<float> Floats;
//...
};
and use like:
my_class a;
a.Ints::add_element(10);
a.Floats::add_element(10.0f);