recursive template inheritance code duplication - c++

#include <iostream>
template< class T, unsigned S >
struct my_iterator;
template< class T >
struct my_iterator< T, 1 >
{
T* p;
};
template< class T, unsigned S >
struct my_iterator : my_iterator< T, S / 2 >
{
static_assert ((S & (S - 1)) == 0, "S must be a power of 2");
using my_iterator< T, S / 2 >::p;
unsigned burp() {return (*p) + S;}
};
int main()
{
int v = 10;
my_iterator< int, 8 > a;
a.p = &v;
std::cout << a.burp() << std::endl;
my_iterator< int, 4 >& b = a;
std::cout << b.burp() << std::endl;
my_iterator< int, 1 > c;
c.p = &v;
std::cout << c.burp() << std::endl; // error: no member named 'burp'
return 0;
}
This will fix the error:
template< class T >
struct my_iterator< T, 1 >
{
unsigned burp() {return (*p) + 1;}
T* p;
};
but in my real code I have many methods, not just burp, all dependent on S and p, that would all need to be implemented twice, once in the general class and once in the specialization. Is there any way to avoid the duplicate code? I saw this similar question:
Avoiding code duplication in a specialized template
but the answer will not work in my case because I'll end up with many copies of p, one at each level of the recursive hierarchy.

Another option, if you have a recursion stop value of 1 which you want to still use, you can just move the stop value to 0...
This way my_iterator<T,1> still has the default implementation.
template< class T, unsigned S >
struct my_iterator;
template< class T >
struct my_iterator< T, 0 >
{
T* p;
};
template< class T, unsigned S >
struct my_iterator : my_iterator< T, S / 2 >
{
static_assert ((S & (S - 1)) == 0, "S must be a power of 2");
using my_iterator< T, S / 2 >::p;
unsigned burp() {return (*p) + S;}
};

An other way is to move specific stuff in an other structure:
template <typename T> struct opt_ptr { T* p; };
// to be able to use std::conditional with non instantiated type.
template <typename T> struct identity { using type = T; };
template<typename T, unsigned S>
struct my_iterator :
std::conditional<S == 1,
identity<opt_ptr<T>>,
identity<my_iterator<T, S / 2>>>::type::type
{
static_assert ((S & (S - 1)) == 0, "S must be a power of 2");
using opt_ptr<T>::p; // Note that you may use this->p to avoid this line
unsigned burp() {return *p + S;}
// Other methods using S and p.
};

You could pass down S to the base template, and move the method there.
template< class T, unsigned S, unsigned N >
struct my_iterator;
template< class T, unsigned S >
struct my_iterator< T,S, 1 >
{
unsigned burp() {return (*p) + S;}
T* p;
};
template< class T, unsigned S, unsigned N = S >
struct my_iterator : my_iterator< T, S, N / 2 >
{
static_assert ((S & (S - 1)) == 0, "S must be a power of 2");
using my_iterator< T,S, N / 2 >::p;
};

Related

How to specialize a template for 2 different values?

Given the code below, I was wondering if it is possible to have a specialization for a set of values. In my example, I want to create an specialization for N=3 or N=4 to use an array of known size. Is it possible to avoid code duplication in this case?
template <typename T, unsigned int N>
class A
{
public:
T* data;
};
template <typename T>
class A<T, 3>
{
public:
T data[3];
};
template <typename T>
class A<T, 4>
{
public:
T data[4];
};
int main()
{
A<int, 1> u;
std::cout << sizeof(u.data) << std::endl; // Size of pointer
A<int, 3> v;
std::cout << sizeof(v.data) << std::endl; // Size of data
A<int, 4> w;
std::cout << sizeof(w.data) << std::endl; // Size of data
return 0;
}
You can use std::enable_if by introducing a default void template parameter in the general case.
template <typename T, unsigned int N, typename = void>
class A
{
public:
T* data;
};
template <typename T, unsigned int N>
class A<T, N, typename std::enable_if<N == 3 || N == 4>::type>
{
public:
T data[N];
};
live wandbox example
If N == 3 || N == 4 is true, then typename std::enable_if<N == 3 || N == 4>::type is well-formed and evaluates to void. The specialization is then chosen.
If N == 3 || N == 4 is false, then typename std::enable_if<N == 3 || N == 4>::type is ill-formed and the specialization is "SFINAEd away". The general case is then chosen.

Const and non const template specialization

I have a class template which I use to get the size of a variable:
template <class T>
class Size
{
unsigned int operator() (T) {return sizeof(T);}
};
This works fine but for strings I want to use strlen instead of sizeof:
template <>
class Size<char *>
{
unsigned int operator() (char *str) {return strlen(str);}
};
The problem is when I create an instance of size with const char * it goes to the unspecialized version. I was wondering if there is a way to capture both the const and non-const versions of char * in on template specialization? Thanks.
Use this technique:
#include <type_traits>
template< typename T, typename = void >
class Size
{
unsigned int operator() (T) {return sizeof(T);}
};
template< typename T >
class Size< T, typename std::enable_if<
std::is_same< T, char* >::value ||
std::is_same< T, const char* >::value
>::type >
{
unsigned int operator() ( T str ) { /* your code here */ }
};
EDIT: Example of how to define the methods outside of the class definition.
EDIT2: Added helper to avoid repeating the possibly long and complex condition.
EDIT3: Simplified helper.
#include <type_traits>
#include <iostream>
template< typename T >
struct my_condition
: std::enable_if< std::is_same< T, char* >::value ||
std::is_same< T, const char* >::value >
{};
template< typename T, typename = void >
struct Size
{
unsigned int operator() (T);
};
template< typename T >
struct Size< T, typename my_condition< T >::type >
{
unsigned int operator() (T);
};
template< typename T, typename Dummy >
unsigned int Size< T, Dummy >::operator() (T)
{
return 1;
}
template< typename T >
unsigned int Size< T, typename my_condition< T >::type >::operator() (T)
{
return 2;
}
int main()
{
std::cout << Size< int >()(0) << std::endl;
std::cout << Size< char* >()(0) << std::endl;
std::cout << Size< const char* >()(0) << std::endl;
}
which prints
1
2
2
And you should also be able to write, of course:
template <>
class Size<const char *>
{
unsigned int operator() (const char *str) {return strlen(str);}
};
template <>
class Size<char *> : public Size<const char *>
{ };
...and, should you need to:
template <size_t size>
class Size<char[size]> : public Size<const char *>
{ };
template <size_t size>
class Size<const char[size]> : public Size<const char *>
{ };
One way is to use a helper function in order to determine if the template type is a char * or a char const *. You can do this with a simple struct. Then you can use SFINAE to select the proper specialization of your Size struct.
#include <cstring>
#include <iostream>
#include <boost/utility/enable_if.hpp>
template<typename T>
struct is_cstring {
enum { value = false };
};
template<>
struct is_cstring<char *> {
enum { value = true };
};
template<>
struct is_cstring<char const *> {
enum { value = true };
};
template<typename T, typename = void>
struct Size;
template<typename T>
struct Size<T, typename boost::disable_if<is_cstring<T> >::type> {
unsigned int operator ()(T const &) const {
return sizeof(T);
}
};
template<typename T>
struct Size<T, typename boost::enable_if<is_cstring<T> >::type> {
unsigned int operator ()(T const &str) const {
return strlen(str);
}
};
int main() {
std::string blah = "afafasa";
char *x = "asdfsadsad";
std::cout << Size<int>()(4) << std::endl;
std::cout << Size<char const *>()("blahblah") << std::endl;
std::cout << Size<char *>()(x) << std::endl;
}
The printed result is:
4
8
10

sizeof variadic template (sum of sizeof of all elements)

Considering the following function :
template<typename... List>
inline unsigned int myFunction(const List&... list)
{
return /* SOMETHING */;
}
What is the most simple thing to put instead of /* SOMETHING */ in order to return the sum of sizeof all arguments ?
For example myFunction(int, char, double) = 4+1+8 = 13
In C++17, use a fold expression:
template<typename... List>
inline constexpr unsigned int myFunction(const List&... list)
{
return (0 + ... + sizeof(List));
}
unsigned myFunction() {return 0;}
template <typename Head, typename... Tail>
unsigned myFunction(const Head & head, const Tail &... tail) {
return sizeof head + myFunction(tail...);
}
Based off of this comment and the following comments on the question, you could use this (note: completely untested)
std::initializer_list<std::size_t> sizeList = {sizeof(List)...}; //sizeList should be std::initializer_list, according to the comments I linked to
return std::accumulate(sizeList.begin(), sizeList.end(), 0);
Two years late but an alternative solution guaranteed to be computed by the compiler (if you don't mind the different syntax):
template < typename ... Types >
struct SizeOf;
template < typename TFirst >
struct SizeOf < TFirst >
{
static constexpr auto Value = (sizeof(TFirst));
};
template < typename TFirst, typename ... TRemaining >
struct SizeOf < TFirst, TRemaining ... >
{
static constexpr auto Value = (sizeof(TFirst) + SizeOf<TRemaining...>::Value);
};
Used as constexpr std::size_t size = SizeOf<int, char, double>::Value; // 4 + 1 + 8 = 13
Here's a template way:
#include <iostream>
template<typename T, typename ...Ts>
class PPackSizeOf
{
public:
static const unsigned int size = sizeof(T) + PPackSizeOf<Ts...>::size;
};
template<typename T>
class PPackSizeOf<T>
{
public:
static const unsigned int size = sizeof(T);
};
template<typename ...Ts>
class FixedSizeBlock
{
private:
char block[PPackSizeOf<Ts...>::size];
public:
};
int main( )
{
FixedSizeBlock<char,long> b;
std::cout << sizeof(b) << std::endl;
return 0;
}
I've just found that :
template<typename... List>
inline unsigned int myFunction(const List&... list)
{
return sizeof(std::make_tuple(list...));
}
But :
1) Do I have the guarantee that the result will always be the same on all compilers ?
2) Do the make_tuple will make and overhead at compile-time ?

template overloading and SFINAE working only with functions but not classes

can someone explain why the compiler accepts only this code
template<typename L, size_t offset, typename enable_if< (offset<sizeof(L)), int >::type =0>
void a_function(){}
template<typename L, size_t offset, typename enable_if< (offset==sizeof(L)), int >::type =0>
void a_function(){}
but not this:
template<typename L, size_t offset, typename enable_if< (offset<sizeof(L)), int >::type =0>
class a_class{};
template<typename L, size_t offset, typename enable_if< (offset==sizeof(L)), int >::type =0>
class a_class{};
The compiler sees the second class template as a redefinition of the first.
You have to use specialization for classes. Typically, it is done with an extra parameter:
template <class P, class dummy = void>
class T;
template <class P>
class T<P, typename enable_if<something, void>::type> {
the real thing
};
Two class (or class template) declarations with the same name should always declare the same class or class template (or be a specialization, in which case it is still the same template).
You probably want to do something like this (ideone.com link):
#include <iostream>
template< typename PL, size_t pOffset, int pC = int( sizeof(PL) ) - int( pOffset ) >= 0 ? ( int( sizeof(PL) ) - int( pOffset ) == 0 ? 0 : 1 ) : -1 >
class TClass
{
};
template< typename PL, size_t pOffset >
class TClass< PL, pOffset, -1 >
{
public:
static int const sI = -1;
};
template< typename PL, size_t pOffset >
class TClass< PL, pOffset, 0 >
{
public:
static int const sI = 0;
};
template< typename PL, size_t pOffset >
class TClass< PL, pOffset, 1 >
{
public:
static int const sI = 1;
};
int main(void )
{
TClass< char, 0 > lC0;
TClass< char, 1 > lC1;
TClass< char, 2 > lC2;
std::cout << lC0.sI << " : " << lC1.sI << " : " << lC2.sI << std::endl;
return ( 0 );
}
Program output:
1 : 0 : -1

Unrolling loops using templates in C++ with partial specialization

I'm trying to use templates to unroll a loop in C++ as follows.
#include <iostream>
template< class T, T i >
struct printDown {
static void run(void) {
std::cout << i << "\n";
printDown< T, i - 1 >::run();
}
};
template< class T >
struct printDown< T, 0 > {
static void run(void) {
std::cout << 0 << "\n";
}
};
int main(void) {
printDown< int, 10 >::run();
return 0;
}
When I compile w/ g++ 3.4.4 in Cygwin, I get the following error.
tmp.cpp:12: error: type T' of
template argument0' depends on
template parameter(s)
What am I doing wrong? Do I need to somehow annotate the 0 to say that it's of type T?
Thanks in advance.
Have you tried int i instead of T i?
Why this happens? From 14.5.5/8,
— The type of a template parameter
corresponding to a specialized
non-type argument shall not be
dependent on a parameter of the
specialization. [ Example:
template <class T, T t> struct C {};
template <class T> struct C<T, 1>; // error
template< int X, int (*array_ptr)[X] > class A {};
int array[5];
template< int X > class A<X,&array> { }; // error
—end example ]
Therefore when you apply partial specialization, the type of 0 is T (dependent on a parameter of the specialization). There are two choices, one is to make it none dependent, e.g., change T i to int i, and second is to apply explicit specialization rather than partial specialization.
Both solutions have been given out by others, so I'm not gonna to repost them here. At least you know the reason. It's defined by standard.
As pointed out by phooji your implementation suffers from a small issue: it quickly generates a long list of calls, which will make compilers choke quickly.
You could work around this by implementing a slightly more complicated version, using binary decomposition. I'll make it generic on a functor too, cause I am lazy.
// Signature
template <Functor F, unsigned N>
struct UnrolledLoop;
We need a helper template, which keeps an offset of the parameter to pass
template <Functor F, unsigned N, unsigned OffSet>
struct UnrolledImpl;
template <Functor F, unsigned OffSet>
struct UnrolledImpl<F, 0, OffSet>
{
static F run(F f) { return f; }
};
template <Functor F, unsigned OffSet>
struct UnrolledImpl<F, 1, OffSet>
{
static F run(F f) { f(OffSet); return f; }
};
template <Functor F, unsigned N, unsigned OffSet>
struct UnrolledImpl
{
static F run(F f) {
F f2 = UnrolledImpl<F, N/2, OffSet>::run(f);
return UnrolledImpl<F, N - N/2, OffSet + N/2>::run(f2);
}
};
And you can implement UnrolledLoop simply:
template <Functor F, unsigned N>
struct UnrolledLoop
{
static F run(F f) { return UnrolledImpl<F, N, 0>::run(f); }
}
Note that you could provide specialization for more values of N (3, 4 for example) to be nicer on the compiler.
What about adding this to your example:
template struct printDown< int, 0 >{
static void run(void) {
std::cout << 0 << "\n";
} };
The compiler cannot cast 0 to int automatically without knowing T's type in advance.
Just found this out. Apparently one can do something like this.
template< class T, T i, bool b = (i == 0) >
struct printDown {
static void run(void) {
std::cout << i << "\n";
printDown< T, i - 1 >::run();
}
};
template< class T, T i >
struct printDown< T, i, true > {
static void run(void) {
std::cout << 0 << "\n";
}
};
I had no idea that could be done. Very Prologish & very nice.
You can make the parameter a type parameter to work this around
template< bool > struct bool_ { };
template< class T, T i, typename = bool_<true> >
struct printDown {
static void run(void) {
std::cout << i << "\n";
printDown< T, i - 1 >::run();
}
};
template< class T, T i >
struct printDown< T, i, bool_<i == 0> > {
static void run(void) {
std::cout << 0 << "\n";
}
};
int main(void) {
printDown< int, 10 >::run();
return 0;
}
This way you can specify any conditions you want in the partial specializations.