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);
Related
The (EBO/EBCO/Empty Base Optimisation) is widely used in STL, but regardless of the implementation differences, the idea seems to be similar: they put EmptyBase and some member into a packed_pair, std::tuple (in implementations where it supports EBCO), or other boost::compressed_pair-look-alikes.
I've found a few links explaining this technique here and here and they also give this "packing" solution as a good one, and by the look of things the only solution everyone uses.
It all boils down to something like this:
template <class EBase>
class SomeClass {
...
packed_pair<EBase, TElem> pack;
};
and then they'll use some getters to get EBase (Allocator/Deleter/...) and the element.
the pack.first() and pack.second() themselves do not look very attractive, for sure, but otherwise nice technique, very useful, except for one situation...
What if, for example, there's no other member to pack the EmptyBase with? What if those members are inherited from a class that doesn't need the EmptyBase, so you cannot pack it there, so the question is: what's next? Looks like we need to find another way...
In those articles they quickly dumped the inheritance-based solution as a naive one, but what if we elaborate a little on it?
#if (__has_cpp_attribute(no_unique_address) || __cplusplus/100 >= 2020)
// [[no_unique_address]] saves the day, thus an easy case is solved
template <class Base>
class EBO {
public:
[[no_unique_address]] Base elem;
EBO(Base const& b) : elem{b} {}
Base& ebo_unwrap() { return elem; }
};
#else
// Specialising so that we don't inherit from something bad :)
template <class Base, bool Use_inheritance>
class EBO_specialized : public Base {
public:
EBO_specialized(Base const& b) : Base{b} {}
Base& ebo_unwrap() { return *static_cast<Base*>(this); }
};
template <class Base>
class EBO_specialized<Base, false> {
public:
Base elem;
EBO_specialized(Base const& b) : elem{b} {}
Base& ebo_unwrap() { return elem; }
};
template <class Base>
class EBO : public EBO_specialized<Base, Type<Base>( is_empty && !is_final )> {
using EBOBase = EBO_specialized<Base, Type<Base>( is_empty && !is_final )>;
public:
EBO(Base const& d) : EBOBase{d} {}
using EBOBase::ebo_unwrap;
};
#endif
What are the potential problems that can arise when doing EBO this way?
let's imagine some use-case now
template <class Deleter>
class SomePointer : PointerBase, EBO<Deleter> {
...
using PointerBase::raw_ptr;
~SomePointer() { EBO<Deleter>::ebo_unwrap() (*raw_ptr); }
};
(Some) other ways to do Empty Base Class Optimisation:
The easiest one, if you develop for C++20 and beyond or you're using a compiler that provides [[no_unique_address]] as an extension for whatever version of C++ language you're using:
template <class Empty>
class SomeClass {
[[no_unique_address]] Empty empty; // and that's it!
};
The most commonly-used one in pre-C++-20 code, seen in places like STL, the "packing" method, also slightly covered both in the question and in the article in comments.
Pros: It packs an empty base class with another member variable of our class.
Cons: It packs an empty base class with another member variable of out class! So much syntactic noise...
The one proposed in the question:
(if we drop some #ifdefs switching to [[no_unique_address]] when it's supported, here's what we get: )
template <class Base, bool Use_inheritance>
class EBO_specialized : public Base {
public:
EBO_specialized(Base const& b) : Base{b} {}
constexpr Base& get() { return *static_cast<Base*>(this); }
};
template <class Base>
class EBO_specialized<Base, false> {
public:
Base elem;
EBO_specialized(Base const& b) : elem{b} {}
constexpr Base& get() { return elem; }
};
template <class Base>
class EBO : public EBO_specialized<
Base, (std::is_empty_v<Base> && !std::is_final_v<Base>)
> {
using EBOBase = EBO_specialized<
Base, (std::is_empty_v<Base> && !std::is_final_v<Base>)
>;
public:
EBO(Base const& d=Base()) : EBOBase{d} {}
using EBOBase::get;
};
The two articles correctly outline some issues with naive inheritance, i.e. without checking the Base class properties. Those problems are:
Base can be final. It'd be an error inheriting from it.
Base can have virtual functions
inheriting from a template parameter can affect whether a member function is virtual.
Now to our implementation: we explicitly check for emptiness via std::is_empty, which will not be the case for a class containing virtual functions and thus a vptr (in the majority of implementations, in ALL implementations I know of). And the second check for is_final rules out the second possibility.
Bonus: can be used with constexpr, for example when you'd like to use C++20's constexpr new. Same is true for all above-mentioned techniques.
The WTF-way, but admit it, it's nice:)
godbolt link
// No inheritance used!
template <class C, bool IsEmpty=std::is_empty<C>::value>
struct MaybeEmpty { /* C is empty */
constexpr MaybeEmpty(C &) noexcept {/* no-op */};
C& get() { // alas, no constexpr reinterpret_cast
return *reinterpret_cast<C*>(this);
}
};
template <class C>
struct MaybeEmpty<C,false> { /* C is not empty */
C obj;
constexpr MaybeEmpty(C & c) noexcept : obj{c} {}
constexpr C& get() {
return obj;
}
};
Since an empty class has no inner state, we can successfully reinterpret_cast anything into it, so here we reinterpret_cast this, which is a pointer to MaybeEmpty, which is itself empty in this instantiation, so sizeof(MaybeEmpty) == sizeof(Base) == 1(somewhat counterintuitively not 0, due to memory layout rules, but anyway, it's empty).
So, as it uses no inheritance, it doesn't suffer from all of the above-mentioned problems. Except for a new, subtle one: we cannot use constexpr in get().
Edit:
4.1.
template <class C, bool IsEmpty=std::is_empty<C>::value>
struct MaybeEmpty {
constexpr MaybeEmpty(C &) noexcept {};
constexpr C get() {
union {MaybeEmpty self; C base;} cast{*this};
return cast.base;
}
};
template <class C>
struct MaybeEmpty<C,false> {
C obj;
constexpr MaybeEmpty(C & c) noexcept : obj{c} {}
constexpr C get() {
return obj;
}
};
godbolt link
this works with constexpr in clang & msvc but not gcc > 9.4...
P.S. If you've spotted a bug, please write in the comments!
I have a (generated) set of classes that look roughly like this when simplified:
class A {
public:
static const int id = 0;
typedef int value_type;
void* data; // actually pointer to int
};
class B {
public:
static const int id = 1;
typedef float value_type;
void* data; // actually pointer to float
};
There are altogether tens of these, with much fewer types. I need to create classes that calculate some derived values for all of these. Now the obvious solution would be using a template like this:
template<class T>
class Derived {
public:
typename T::value_type value;
void update(const void* data) {
value = *static_cast<typename T::value_type*>(data);
// do some calculations
}
};
But this is going to instantiate a separate class for every single parameter class A, B, and so on; most of which will be identical. The other solution would be an obvious template class like this:
template<typename T>
class Derived2 {
public:
T value;
void update(const void* data) {
value = *static_cast<T*>(data);
}
};
This would be updating the code using this class manually if the schema that classes A, B, etc., are generated from changes. Is there a way to use the value_type typedefs to generate instantiations of Derived2<int>, Derived2<float> etc., or at least match the types of manually parametrized instantiations to types A, B, etc.?
This is an embedded system, so the target is reducing the amount of identical code, even if it leads to more convoluted C++ code. Replacing the void*s with actual types would lead to code explosion in other parts of the program, so it is not done.
As posted in the comments this will do what you need:
template<class T> struct Derived : Derived2<typename T::value_type> { };
I'm trying to write a smart pointer wrapper (contains a boost shared_ptr or scoped_ptr or another smart pointer wrapper); each wrapper type injects a bit of extra functionality (eg. logging usage, lazy init, verifying correct construction/destruction order, etc) but I want them to be as invisible as possible to the user (such that I could swap in/out wrappers simply by changing a single typedef, and possibly some constructor code, but none of the usage code).
Normal usage is trivial:
template<typename T>
class some_smart_ptr_wrapper
{
public:
typedef typename T::value_type value_type;
...
value_type* get() { /*do something magic*/ return m_ptr.get(); }
const value_type* get() const { /*do something magic*/ return m_ptr.get(); }
// repeat for operator->, operator*, and other desired methods
private:
T m_ptr;
};
typedef some_smart_ptr_wrapper< boost::shared_ptr<int> > smart_int;
smart_int p;
(Now all other code can use p indistinguishably from a shared_ptr, at least for the defined operations, and I can add extra wrappers just by changing the typedef.)
Multiple wrappers can be used simultaneously simply by nesting them as you'd expect, and only the code that declares (and sometimes initialises) the variable needs to care.
Occasionally though it's useful to be able to get the "basic" shared/scoped_ptr from a wrapper (particularly to pass a shared_ptr as an argument to a function that doesn't need to trigger the functionality added by the wrappers); for a single wrapper layer it's easy:
T& getPtr() { return m_ptr; }
const T& getPtr() const { return m_ptr; }
But this doesn't scale nicely to multiple wrapper layers (the caller has to do p.getPtr().getPtr().getPtr() the correct number of times).
What I'd like to be able to do is to declare getPtr() such that:
if T implements getPtr(), then it returns m_ptr.getPtr() (whatever type that is).
if T does not implement getPtr(), then it returns m_ptr.
it's still available in both const and non-const flavours, as you'd expect.
The net result of which is that a single call to getPtr() from the outside code will "walk up" the chain to the original smart pointer, since that will be the only one that doesn't implement getPtr().
I'm fairly sure that the solution will involve SFINAE and boost::enable_if; I've had a bit of a play towards trying to get something like that to work but haven't had much luck thus far.
Solutions or completely alternate approaches both welcomed; note that I would like it to work in both VC++2008 and GCC (ie. no C++11, sadly).
(1) Declare a special member typename which is unique inside:
template<typename T>
class some_smart_ptr_wrapper
{
public:
typedef T smart_type; // <-- unique name
...
};
(2) Wrap getPtr() inside a template function wrapper:
template<typename T>
class some_smart_ptr_wrapper
{
...
public:
T& getPtr () { return m_ptr; }
typename My_sfinae<T>::RealType& getFinalPtr ()
{ return My_sfinae<T>::getPtr(m_ptr); }
...
};
(3) Where My_sfinae is implemented as usual:
template<typename T>
struct void_ { typedef void type; };
template<typename T, typename = void>
struct My_sfinae {
typedef T RealType;
static T& getPtr (T &p) { return p; }
}; //^^^^^^^^^ business logic!
template<typename T>
struct My_sfinae<T, typename void_<typename T::smart_type>::type> {
typedef typename My_sfinae<typename T::smart_type>::RealType RealType;
static RealType& getPtr (T &p)
{ return My_sfinae<typename T::smart_type>::getPtr(p.getPtr()); }
};
As you can see, My_sfinae removes all your wrappers recursively and finally you are left with the final m_ptr.
Here is the demo.
It is, actually, a simple problem: just use Overloading :)
template <typename T>
boost::scoped_ptr<T>& get_pointer(boost::scoped_ptr<T>& sp) { return sp; }
template <typename T>
boost::shared_ptr<T>& get_pointer(boost::shared_ptr<T>& sp) { return sp; }
// One overload per "wrapper"
template <typename T>
typename get_pointer_type<T>::type& get_pointer(some_wrapper<T>& p) {
return get_pointer(p.getPtr());
}
The trick is then to correctly specialize get_pointer_type for each wrapper.
template <typename T>
struct get_pointer_type { typedef T type; };
template <typename T>
struct get_pointer_type< some_wrapper<T> > {
typedef typename get_pointer_type<T>::type type;
};
The closest thing that comes to my mind is the paper written by Bjarne Stroustrup called Wrapping C++ Member Function Calls.
This paper presents a simple, general, and efficient solution to the old problem of
‘‘wrapping’’ calls to an object in pairs of prefix and suffix code. The solution is also
non-intrusive, applies to existing classes, allows the use of several prefix/suffix pairs, and
can be implemented in 15 simple lines of Standard C++. A robust version of the wrapper
is also presented. The claim of efficiency is backed by measurement.
I'm building a datastructure class with an std-like interface, and implementing different iterators for the data structure.
Conceptually, what I would like to do is something like this:
template <class DataT>
class DataStructure
{
protected:
DataT& Data;
public:
DataStructure(DataT& data) : Data(data) {}
class BaseIterator
{
public:
BaseIterator()
{
cout<<"BaseIterator"<<endl;
}
};
class DerrivedIterator1 : public BaseIterator
{
public:
DerrivedIterator1()
{
cout<<"DerrivedIterator1"<<endl;
}
};
class DerrivedIterator2 : public BaseIterator
{
public:
DerrivedIterator2()
{
cout<<"DerrivedIterator2"<<endl;
}
};
template<class IterT>
IterT Begin()
{
//none-specialized implementation. Possibly throw exception
}
template<>
DerrivedIterator1 Begin<DerrivedIterator1>()
{
//Find beginning for DerrivedIterator1
}
template<>
DerrivedIterator2 Begin<DerrivedIterator2>()
{
//Find beginning for DerrivedIterator1
}
};
But this of course does not compile since C++ doesn't allow to specialize template member functions in none-specialized template containers.
The obvious workaround is of course to declare 2 different functions: Begin_Iterator1 and Begin_Iterator2 and be done with it. But I'm looking for a workaround that doesn't change the interface.
Any ideas?
Edit: I forgot to mention that this is for a HW assignment and so boost and even std is not an option.
Function templates cannot be specialized in C++, point.
It does not matter whether they are members of template or not, specialization of function templates is not allowed. Normally when using argument types to infer the template arguments, overloading does the same specialization would, so specialization for functions (and the associated extra complexity in overload resolution and such) was not deemed necessary.
You however don't have any arguments to infer on and would instantiate the templates manually. No,
DataStructure::DerivedIterator1 i = dataStructure.Begin();
would not work as you wrote the code, because type inference, just like overload resolution is only done on the arguments, not expected return value. You'd have to write:
DataStructure::DerivedIterator1 i = dataStructure.Begin<DataStructure::DerivedIterator1>();
and that has zero benefit over:
DataStructure::DerivedIterator1 i = dataStructure.BeginIterator1();
However, the first expression can be made to work with some wizardry. First you have to define BeginIterator1 and BeginIterator2 and than you'd do a temporary to late-decide which one to construct:
class DataStructure {
...
class BeginIteratorConstructor {
DataStructure &dataStructure;
public:
BeginIteratorConstructor(DataStructure &ds) : dataStructure(ds) {}
operator DerivedIterator1() { return dataStructure.BeginIterator1(); }
operator DerivedIterator2() { return dataStructure.BeginIterator2(); }
};
BeginIteratorConstructor Begin() { return BeginIteratorConstructor(*this); }
...
};
Now dataStructure.Begin() will return a temporary something, that will call BeginIterator1 if you cast it to DerivedIterator1 or call BeginIterator2 when you cast it to DerivedIterator2. If you pass it to something where the compiler can't decide which one to cast to, it will die either because of ambiguous overload or because BeginIteratorConstructor is not in fact iterator and you'll have to cast it explicitly.
(You should carefully make as much of the BeginIteratorConstructor private, but I am not sure how far will the compiler allow you to go, so you'd have to experiment a bit)
You can use a tagging system, which will save you from partially specialized functions inside class templates:
struct base_iter_tag{};
struct der1_iter_tag{};
struct der2_iter_tag{};
template<class T>
struct iter_type;
template<>
struct iter_type<BaseIterator>{
typedef base_iter_tag tag;
};
template<>
struct iter_type<DerivedIterator1>{
typedef der1_iter_tag tag;
};
template<>
struct iter_type<DerivedIterator2>{
typedef der2_iter_tag tag;
};
template<class IterT>
IterT Begin(){
return DoBegin(typename iter_type<IterT>::tag());
}
BaseIterator DoBegin(base_iter_tag){
// ...
}
DerivedIterator1 DoBegin(der1_iter_tag){
// ...
}
DerivedIterator2 DoBegin(der2_iter_tag){
// ...
}
This is essentially what the standard library does with the iterator_traits<T>::iterator_category and overloaded functions depending on the category (e.g. forward_iterator_tag, random_access_iterator_tag, etc...).
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.