C++ Template class methods that do not use template parameter - c++

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]);

Related

encapsulate many type of Datastructure<T> and expose all functionality of them

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.

sfinae away a destructor

I am implementing something very similar to std::vector but uses array on the stack instead of memory allocation.
The d-tor calls a function that uses SFINAE.
If value_type is POD the function have empty body.
If value_type is normal class such std::string, the function have a body and destroy all the data properly.
Now, I want to be able to use this new std::vector as constexpr. However even the c-tor is declared constexpr, the code does not compiles because the class have non trivial d-tor.
Here is small part of the code:
template<typename T, std::size_t SIZE>
class SmallVector{
constexpr SmallVector() = default;
~SmallVector(){
destructAll_<value_type>();
}
// ...
template<typename X>
typename std::enable_if<std::is_trivially_destructible<X>::value == true>::type
destructAll_() noexcept{
}
};
Is there anything I can do to make class be constexpr if value_type is POD and keeping functionality for non POD data types.
(Not at the same time of course)
until C+20
Unfortunately, there is no way to enable/disable destructor with SFINAE, nor with future concepts. That is because destructos:
can't be templated
can't have arguments
can't have a return type
What you can do is specialize whole class, or better yet, create a base class that contains only the construct/destruct and basic access and specialize that.
template <class T, class Enable = void>
struct X {
~X() {}
};
template <class T>
struct X<T, std::enable_if_t<std::is_pod<T>::value>> {
};
static_assert(std::is_trivially_destructible<X<int>>::value);
static_assert(!std::is_trivially_destructible<X<std::vector<int>>>::value);
C++ 20
As far as I can tell you can constraint a destructor and get exactly what you want in a very simple and elegant solution:
template<typename T, std::size_t SIZE>
class SmallVector{
public:
constexpr SmallVector() = default;
~SmallVector() requires std::is_trivially_destructible_v<T> = default;
~SmallVector()
{
}
};
static_assert(std::is_trivially_destructible_v<SmallVector<int, 4>>);
static_assert(!std::is_trivially_destructible_v<SmallVector<std::string, 4>>);
However this is a brand new feature and there have been some changes lately (e.g. see Disable non-templated methods with concepts) and the compiler support is still sketchy. gcc compiles this just fine, while clang is confused by the fact that there are two definitions of the destructor godbolt
The example of if constexpr in destructor. (C++17 required)
template<typename Tp, typename TLock>
struct LockedPtr {
private:
Tp *m_ptr;
TLock *m_lk;
void prelock(std::mutex *mtx) { mtx->lock(); }
void prelock(std::atomic_flag *atom) { while(atom->test_and_set(std::memory_order_acquire)); }
public:
LockedPtr(Tp *ptr, TLock *mtx)
: m_ptr(ptr), m_lk(mtx) {
prelock(mtx);
}
~LockedPtr() {
if constexpr (std::is_same_v<TLock, std::mutex>)
((std::mutex *)m_lk)->unlock();
if constexpr (std::is_same_v<TLock, std::atomic_flag>)
((std::atomic_flag *)m_lk)->clear(std::memory_order_release);
}
};
These code is the part of RAII locked smart pointer, to adopt to normal std::mutex and spinlock by std::atomic_flag.
Using function overload to match different type in constructor.
Match type by if constexpr and make something unconvertable to pointer in destructor.

Variadic templates and new

I have this class template:
template<class... T>
class Test {
std::vector<TestCase*> test_cases;
public:
Test() {
// Here, for each T an instance should be added to test_cases.
test_cases.push_back((new T)...);
}
};
This works fine for one template argument, but for multiple arguments I get this error:
error: too many arguments to function call, expected 1, have 2
How can I use variadic templates with new this way? What is the correct syntax?
EDIT: I think my question wasn't quite clear. What I want is this:
Test<TestCase1, TestCase2, TestCase3>;
// The constructor will then be:
test_cases.push_back(new TestCase1);
test_cases.push_back(new TestCase2);
test_cases.push_back(new TestCase3);
My compiler is clang 163.7.1 with this flag: -std=c++0x.
vector::push_back expects one parameter so you can't expand the variadic template in the function call.
Also I added a template parameter for the base class (from which all other classes derive).
Here's something that compiles.
struct base{};
struct d0 : base{};
struct d1 : base{};
struct d2 : base{};
#include <vector>
// termination condition for helper function
template <class T>
void add(std::vector<T*>&) {
}
// helper function
template <class T, class Head, class... Tail>
void add(std::vector<T*>& v) {
v.push_back(new Head());
add<T, Tail...>(v);
}
template <class T, class ... U>
class test
{
std::vector<T*> vec;
public:
test() {
add<T, U...>(vec);
}
};
int main()
{
test<base, d0,d1,d2> t;
}
You can accomplish this, but it’s a bit roundabout since you write the expression directly. You need to call push_back once for each argument in the variadic template argument list.
How do you achieve this? Well, by calling a recursive function once for each template argument:
template <typename Base, typename T1, typename T2, typename... T>
void fill(std::vector<Base*>& vec) {
vec.push_back(new T1);
fill<Base, T2, T...>(vec);
}
template <typename Base, typename T1>
void fill(std::vector<Base*>& vec) {
vec.push_back(new T1);
}
Here we have two overloads of the fill function, one with a variadic template argument list and one without – this is the recursion base case. As long as there are still at least two template arguments, the first version gets called. If there is only a single argument left, the second argument is called instead.
Call it like this in the constructor:
fill<TestCase, T...>(test_cases);
Pack expansion can only happen in a select number of situations and doesn't work for arbitrary expressions or statements. However, since one of those situation is list-initialization and since the order of operations is defined for the brace initializers of list-initialization syntax, it's always possible to expand an arbitrary statement. To wit:
typedef std::initializer_list<int> expand;
expand { ( test_cases.push_back(new T), void(), 0 )... };
The void() trick is to suppress any invocation of an overloaded operator,. Completely irrelevant here but I have included it since it may be useful when refactoring the functionality in a macro:
#define EXPAND( exp ) \
std::initializer_list<int> { ( (exp), void(), 0 )... }
// No use of '...', it's in the macro body
EXPAND(( test_cases.push_back(new T) ));
On a related note, in this particular case you can use vector's initializer_list support by writing the constructor as follows
Test()
:test_cases{ new T ... }
{ }
Or by using assignment if for any reason you can't use constructor initializers
Test() {
test_cases = { new T ... };
}
Maybe you want a tuple inside your std::vector? Not sure if this is what you intended, but this compiles at least on my G++ 4.6.1 :D
#include <vector>
#include <utility>
#include <functional>
#include <string>
template<class... T>
class Test {
std::vector<std::tuple<T*...>> test_cases;
public:
Test() {
// Here, for each T an instance should be added to test_cases.
test_cases.push_back(std::tuple<T*...>((new T)...));
}
};
int main()
{
Test<int, float> foo;
Test<std::string, double> bar;
}
It strikes me you want a dynamic vector of any type (although not personally looking myself, I was told by a friend there was apparently something like this in the boost library), as opposed to a template vector.
A template vector is basically a vector that can assume any of one defined type (either all ints, or all doubles, or all floats but not ints and doubles and floats).
The reason there isn't a class like this conventionally is because each item takes up a different block size in memory (a char is a byte, an int could be 4 bytes etc etc), and it would take additional resources on look-up to know what to expect (normal storage is contiguous... which a vector is, given it is 'basically' an array).
If you're looking to build your own (I tried), you're looking at void * pointers, dynamic memory allocation and a whole host of headaches involving typecasting (I am unaware of any automated method to correctly typecast an item behind the scenes, but others might be able to chip in).

Template classes with specialised constructors

Consider the following contrived example of a templated array definition:
template <typename t, unsigned int n> class TBase
{
protected:
t m_Data[n];
//...
};
template <typename t, unsigned int n> class TDerived : public TBase<t, n>
{
TDerived()
{
}
};
I can specialize this type to provide a non-default constructor for an array of length 2 as follows:
template <typename t> class TDerived<t, 2> : public TBase<t, 2>
{
public:
TDerived(const t& x0, const t& x1)
{
m_Data[0] = x0;
m_Data[1] = x1;
}
};
int main()
{
TDerived<float, 2> Array2D_A(2.0f, 3.0f); //uses specialised constructor
TDerived<float, 3> Array3D_A; //uses default constructor
return 0;
}
Is there some other way I can create a class that has different constructor options constrained against template parameters at compile-time without the requirement for a complete class specialisation for each variation?
In other words, is there some way I can have specialised constructors in the TBase class without the need for the intermediary step of creating TDerived whilst preserving the functionality of TBase?
I think deriving your class from a base class is not relevant to the question here, that's a mere implementation detail. What you really seem to be after is if there's a way to partially specialize member functions, like the constructor. Do you want something like this?
template <typename T, int N> class Foo
{
Foo(); // general
template <typename U> Foo<U, 2>(); // specialized, NOT REAL CODE
};
This doesn't work. You always have to specialize the entire class. The reason is simple: You have to know the full type of the class first before you even know which member functions exist. Consider the following simple situation:
template <typename T> class Bar
{
void somefunction(const T&);
};
template <> class Bar<int>
{
double baz(char, int);
};
Now Bar<T>::somefunction() depends on T, but the function only exists when T is not int, because Bar<int> is an entirely different class.
Or consider even another specialization template <> class Bar<double> : public Zip {}; -- even the polymorphic nature of a class can be entirely different in a specialization!
So the only way you can provide specializations new declarations of members, including constructors, is by specializing the entire class. (You can specialize the definition of existing functions, see #Alf's answer.)
There are basically two options I see for this:
Use a variadic function for construction (ie. "..." notation), you can use the value n inside that function to get your arguments from the stack. However, the compiler will not check at compile time if the user provides the correct number of arguments.
Use some serious template magic to allow a call chaning initialization, that would look like this: vector(2.0f)(3.0f). You can actually build something that at least ensures the user does not provide too many arguments here. However tha mechanism is a little more involved, I can assemble an example if you want.
You can always specialize a member, e.g.
#include <stdio.h>
template< class Type >
struct Foo
{
void bar() const
{ printf( "Single's bar.\n" ); }
};
template<>
void Foo< double >::bar() const
{ printf( "double's bar.\n" ); }
int main()
{
Foo<int>().bar();
Foo<double>().bar();
}
But you want effectively different signatures, so it's not directly a case of specializing a member.
One way forward is then to declare a constructor with a single argument, of a type dependent on the template parameters.
Then you can specialize that, as you want.
Cheers & hth.,
Since constructor is a function, you need to fully specialize the containing class to address your specific problem. No way out.
However, functions cannot be partially specialized (in all compilers). So suppose if you know that you need n = 2 when t = int or double then following is one alternative.
template<>
TDerived<int,2>::TDerived()
{
//...
}
template<>
TDerived<double,2>::TDerived()
{
//...
}
and so on.
[Note: If you use MSVC, then I think it supports partial specialization; in that case you can try:
template<typename t>
TDerived<t,2>::TDerived()
{
//...
}
though, I am not sure enough for that.]
You could give the most common definitions in the non-specialized class and static_assert (BOOST_STATIC_ASSERT for non C++0x) on the array length. This could be considered a hack but is a simple solution to your problem and safe.
template<typename T, unsigned int n>
struct Foo {
Foo(const T& x) { static_assert(n == 1, "Mooh!"); }
Foo(const T& x1, const T& x2) { static_assert(n == 2, "Mooh!"); }
};
The "evil" way would be variadic arguments.
template<typename T, unsigned int n>
struct Foo {
Foo(...) {
va_list ap;
va_start(ap, n);
for(int j=0; j < n; ++j)
bork[j] = va_arg(ap, T);
va_end(ap);
}
};
Then there is also C++0x and the good old make_something trick which is more difficult then one would think.
template<typename... T, unsigned int n>
Foo<T, n> make_foo(T&&...) {
// figure out the common_type of the argument list
// to our Foo object with setters or as a friend straight to the internals
Foo< std::common_type< T... >::type, sizeof(T) > foo;
// recursive magic to pick the list apart and assign
// ...
return foo;
}

Inheritance vs Specialization

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.