Different behaviour of function for arrays and pointers - c++

I'm trying to develop a function with different behaviour for arrays and pointers.
It could be achieved for classes by partial specialization, but it doesn't work on functions!
int i = 0;
some_func( &i ); // pointer
int arr[ 3 ] = { 0 };
some_func( arr ); // array
In second case inside of function some_func parameter type is int*, and there is no way to find out, that it's actually int[3].
On the other hand, if I use class template specialization, I'd have to specify array type explicitly:
template< typename T >
struct S
{
static void some_func( T t ) { ... }
};
template< typename T, size_t N >
struct S< T[ N ] >
{
static void some_func( T t[ N ] ) { ... }
};
// ...............
int arr[ 3 ] = { 0 };
S< int[ 3 ] >::some_func( arr ); // Works,
// but specifying type explicitly is not convenient
For now I've solved the problem with macro define (to be precise, I only need precise sizeof for arrays).
Is there any way to solve it without turning to the dark side of macro definitions?

Take the array by reference:
template< typename T >
void some_func( T *t ) { ... }
template< typename T, size_t N >
void some_func( T (&t)[ N ] ) { ... }

Here I use C++11 style programming in C++03 to do SFINAE and send my arrays at one overload, and non-arrays at another:
#include <iostream>
struct false_type { enum { value = false }; };
struct true_type { enum { value = true }; };
template<typename T>
struct is_array:false_type {};
template<typename T, std::size_t N>
struct is_array<T[N]>:true_type {};
template<bool b,typename T=void>
struct enable_if {};
template<typename T>
struct enable_if<true, T> { typedef T type; };
template<typename T>
typename enable_if< is_array<T>::value>::type some_func( T& array, int unused=0 )
{
std::cout << "array\n";
}
template<typename T>
typename enable_if< !is_array<T>::value>::type some_func( T const& not_array )
{
std::cout << "pointer\n";
}
int main() {
int x[3];
some_func( x );
int y;
some_func( &y );
}

Related

Compile-time C++ function to check whether all template argument types are unique

There is a nice question (Which substitution failures are not allowed in requires clauses?) proposing the next problem.
One needs to write a compile-time function template<typename... Ts> constexpr bool allTypesUnique() that will return true if all argument types are unique, and false otherwise. And the restriction is not to compare the argument types pairwise. Unfortunately, the answer only explains why such function cannot be implemented with some particular approach.
I think the solution can be achieved using multiple inheritance. The idea is to make a class inherited from a number of classes: one for each type T in Ts. And each such class defines a virtual function with a signature depending on T. If some T is found more than once in Ts then function f in a child class will override the function in a base class and it can be detected:
template<typename> struct A{};
template<typename T, typename... Ts>
struct B : B<Ts...> {
using B<Ts...>::f;
constexpr virtual void f(A<T>, bool & unique) { if( ++count > 1 ) unique = false; }
int count = 0;
};
template<typename T>
struct B<T> {
constexpr virtual void f(A<T>, bool & unique) { if( ++count > 1 ) unique = false; }
int count = 0;
};
template<typename... Ts>
constexpr bool allTypesUnique() {
B<Ts...> b;
bool res = true;
( b.f( A<Ts>{}, res ), ... );
return res;
}
int main() {
static_assert( allTypesUnique<void>() );
static_assert( allTypesUnique<void, int&>() );
static_assert( !allTypesUnique<int&, int&>() );
static_assert( allTypesUnique<char, short, int>() );
static_assert( !allTypesUnique<char, short, char>() );
}
Demo: https://gcc.godbolt.org/z/8jhnE7P11
Just curious, is the solution correct and is there a simpler solution for this problem?
A simpler solution can be obtained in compilers supporting class size optimization via C++20 attribute [[no_unique_address]] for empty members. If all class empty members have distinct types, then its sizeof will be 1. If some member types are repeating then they cannot share the same address and sizeof will be more than 1.
Solution code:
template<typename> struct A{};
template<typename T, typename... Ts>
struct B : B<Ts...> {
[[no_unique_address]] A<T> a;
};
template<typename T>
struct B<T> {
[[no_unique_address]] A<T> a;
};
template<typename... Ts>
constexpr bool allTypesUnique() {
if constexpr (sizeof...(Ts) <= 1 )
return true;
else
return sizeof(B<Ts...>) == 1;
}
int main() {
static_assert( allTypesUnique<void>() );
static_assert( allTypesUnique<void, int&>() );
static_assert( !allTypesUnique<int&, int&>() );
static_assert( allTypesUnique<char, short, int>() );
static_assert( !allTypesUnique<char, short, char>() );
}
Demo: https://gcc.godbolt.org/z/577EP1774
A single constexpr function can be constructed to answer this question:
template <class T, class... Ts>
constexpr bool unique_types()
{
if constexpr (sizeof...(Ts)) {
return !(std::is_same_v<T,Ts> || ...) && unique_types<Ts...>();
}
return true;
}
Demo
the code above is the compile time equivalent of
for (int i(0); i < n; ++i)
for (int j(i + 1); j < n; ++j)
{ /* check type[i] vs type[j] */ }
If you want any variation in comparison (e.g. consider int same as int&) just modify the std::is_same_v (e.g. std::is_same_v<std::decay_t<T>, std::decay_t<Ts>>)
If you use virtual base classes depending on each of the given types, you will get exact one base class instance for every unique type in the resulting class. If the number of given types is the number of generated base classes, each type was unique. You can "measure" the number of generated base classes by its size but must take care that you have a vtable pointer inside which size is implementation dependent. As this, each generated type should be big enough to hide alignment problems.
BTW: It works also for reference types.
template < typename T> struct AnyT { char i[128]; };
template < typename FIRST, typename ... T>
struct CheckT: virtual AnyT<FIRST>, virtual CheckT<T...> { };
template < typename FIRST >
struct CheckT<FIRST>: virtual AnyT<FIRST> {};
template < typename ... T>
constexpr bool allTypesUnique()
{
using T1 = CheckT<int>;
using T2 = CheckT<bool, int>;
constexpr std::size_t s1 = sizeof( T1 );
constexpr std::size_t s2 = sizeof( T2 );
constexpr std::size_t diff = s2 - s1;
constexpr std::size_t base = s1 - diff;
constexpr std::size_t measure = sizeof( CheckT< T...> );
return !((sizeof...(T)*diff+base) - measure);
}
int main() {
static_assert( allTypesUnique<void>() );
static_assert( allTypesUnique<void, int>() );
static_assert( !allTypesUnique<void, void>() );
static_assert( allTypesUnique<char, short, int>() );
static_assert( !allTypesUnique<char, short, char>() );
}
Demo
I think you can try to elaborate on using compile-time type ids.
Here is a partly implemented C++14 version (compile-time sorting is required):
#include <cstddef>
#include <type_traits>
#include <utility>
namespace detail {
template<typename T>
struct type_id {
constexpr static int value{};
};
template<const int *const A, const int *const B>
struct same_address : std::false_type {};
template<const int *const A>
struct same_address<A, A> : std::true_type {};
}// namespace detail
// TODO: implement
template<const int *const... I>
struct sort_array {
using type = std::integer_sequence<const int *const, I...>;
};
template<typename>
struct find_duplicates;
template<const int *const A, const int *const B, const int *const... I>
struct find_duplicates<std::integer_sequence<const int *const, A, B, I...>> {
constexpr static bool value = std::conditional_t<detail::same_address<A, B>::value,
std::true_type,
find_duplicates<std::integer_sequence<const int *const, B, I...>>>::value;
};
template<>
struct find_duplicates<std::integer_sequence<const int *const>> {
constexpr static bool value = false;
};
template<const int *const I>
struct find_duplicates<std::integer_sequence<const int *const, I>> {
constexpr static bool value = false;
};
template<typename... T>
constexpr bool all_types_unique() {
return !find_duplicates<typename sort_array<&detail::type_id<T>::value...>::type>::value;
};
int main() {
static_assert(detail::same_address<&detail::type_id<int>::value,
&detail::type_id<int>::value>::value,
"");
static_assert(!detail::same_address<&detail::type_id<int>::value,
&detail::type_id<double>::value>::value,
"");
static_assert(all_types_unique<>(), "");
static_assert(all_types_unique<int>(), "");
static_assert(all_types_unique<int, double>(), "");
static_assert(all_types_unique<int, double, char>(), "");
static_assert(!all_types_unique<int, int>(), "");
static_assert(!all_types_unique<int, int, int>(), "");
return 0;
}
https://godbolt.org/z/E4G6YchE5

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

Type sensitive tuple visitor

Suppose I have a std::tuple made up of types like
struct A {
static void tip();
};
struct B {
static void tip();
};
struct Z {
};
std::tuple<const A&,const B&,const Z&> tpl;
Yes, I need separate A, B. (The implementation of ::tip() differs for each type.) What I try to implement is a type-sensitive "visitor" that iterates through the tuple starting from the beginning to the end. Upon visiting a particular element of type T a function should be called depending on whether T has the ::tip() method or not. In the simple example of above only A and B have ::tip() implemented and Z not. So, the iterator should call twice the function for types with the ::tip() method and once the other function.
Here is what I came up with:
template< int N , bool end >
struct TupleIter
{
template< typename T , typename... Ts >
typename std::enable_if< std::is_function< typename T::tip >::value , void >::type
static Iter( const T& dummy , const std::tuple<Ts...>& tpl ) {
std::cout << "tip\n";
std::get<N>(tpl); // do the work
TupleIter<N+1,sizeof...(Ts) == N+1>::Iter( std::get<N+1>(tpl) , tpl );
}
template< typename T , typename... Ts >
typename std::enable_if< ! std::is_function< typename T::tip >::value , void >::type
static Iter( const T& dummy , const std::tuple<Ts...>& tpl ) {
std::cout << "no tip\n";
std::get<N>(tpl); // do the work
TupleIter<N+1,sizeof...(Ts) == N+1>::Iter( std::get<N+1>(tpl) , tpl );
}
};
template< int N >
struct TupleIter<N,true>
{
template< typename T , typename... Ts >
static void Iter( const std::tuple<Ts...>& tpl ) {
std::cout << "end\n";
}
};
I use a dummy instance of the type of the element at the iterator position and decide via enable_if which function to call. Unfortunately this doesn't work/isn't a nice solution:
The compiler complains about recursive instantiation
The const T& dummy is not a clean solution
I was wondering if enable_if is the right strategy to do the decision and how can one recursively iterate through the std::tuple capturing the first type and keeping all the remaining arguments in vital state. Read through How to split a tuple? but it doesn't do any decision.
How can one implement such a thing in a correct and portable way in C++11?
Well, it was harder than I expected, but this works.
Some things you were doing wrong/that I modified:
You can't evaluate this: std::is_function< typename T::tip >::value, since T::tip is not a type. Even if this could be evaluated, what would happen when T::tip does not exist? Substitution would still fail.
Since you use const references as your tuple's inner types, you had to clean them before trying to find the tip member inside them. By cleaning I mean removing const and removing the reference.
That dummy type stuff was not a good idea, there was no need to use that parameter. You can achieve the same thing using std::tuple_element, which retrieves the i-th type from a tuple.
I modified TupleIter's template parameters to the following, which means:
"TupleIter that processes the index-th type, inside a tuple of size n".
template<size_t index, size_t n>
struct TupleIter;
The whole code is this:
#include <tuple>
#include <iostream>
#include <type_traits>
struct A {
static void tip();
};
struct B {
static void tip();
};
struct Z {
};
// Indicates whether the template parameter contains a static member named tip.
template<class T>
struct has_tip {
template<class U>
static char test(decltype(&U::tip));
template<class U>
static float test(...);
static const bool value = sizeof(test<typename std::decay<T>::type>(0)) == sizeof(char);
};
// Indicates whether the n-th type contains a tip static member
template<size_t n, typename... Ts>
struct nth_type_has_tip {
static const bool value = has_tip<typename std::tuple_element<n, std::tuple<Ts...>>::type>::value;
};
// Generic iteration
template<size_t index, size_t n>
struct TupleIter
{
template< typename... Ts >
typename std::enable_if< nth_type_has_tip<index, Ts...>::value , void >::type
static Iter(const std::tuple<Ts...>& tpl)
{
std::cout << "tip\n";
TupleIter<index + 1, n>::Iter(tpl );
}
template< typename... Ts >
typename std::enable_if< !nth_type_has_tip<index, Ts...>::value , void >::type
static Iter(const std::tuple<Ts...>& tpl) {
std::cout << "no tip\n";
TupleIter<index + 1, n>::Iter(tpl );
}
};
// Base class, we've reached the tuple end
template<size_t n>
struct TupleIter<n, n>
{
template<typename... Ts >
static void Iter( const std::tuple<Ts...>& tpl ) {
std::cout << "end\n";
}
};
// Helper function that forwards the first call to TupleIter<>::Iter
template<typename... Ts>
void iterate(const std::tuple<Ts...> &tup) {
TupleIter<0, sizeof...(Ts)>::Iter(tup);
}
int main() {
A a;
B b;
Z z;
std::tuple<const A&,const B&,const Z&> tup(a,b,z);
iterate(tup);
}
Here is another take on the question, very similar to mfontanini answer, but showcasing:
boost::fusion::for_each (instead of manually iterate over the tuple).
A variant for implementing has_type using an expression-based SFINAE approach, that I feel a little bit simpler to follow than the usual sizeof trick.
#include <boost/tuple/tuple.hpp>
#include <boost/fusion/include/boost_tuple.hpp>
#include <boost/fusion/algorithm.hpp>
#include <iostream>
struct nat // not a type
{
private:
nat();
nat(const nat&);
nat& operator=(const nat&);
~nat();
};
template <typename T>
struct has_tip
{
static auto has_tip_imp(...) -> nat;
template <typename U>
static auto has_tip_imp(U&&) -> decltype(U::tip());
typedef decltype(has_tip_imp(std::declval<T>())) type;
static const bool value = !std::is_same<type, nat>::value;
};
struct CallTip
{
template<typename T>
typename std::enable_if<has_tip<T>::value>::type
operator()(T& t) const
{
std::cout << "tip\n";
T::tip();
}
template<typename T>
typename std::enable_if<!has_tip<T>::value>::type
operator()(T& t) const
{
std::cout << "no tip\n";
return;
}
};
struct A {
static void tip(){}
};
struct B {
static void tip(){}
};
struct Z {
};
int main()
{
A a;
B b;
Z z;
boost::tuple<const A&,const B&,const Z&> tpl(a, b, z);
boost::fusion::for_each(tpl, CallTip());
}
Note that if your compiler support variadic template you can use std::tuple instead of boost::tuple inside fusion::for_each by including #include<boost/fusion/adapted/std_tuple.hpp>
Edit :
As pointed by Xeo in the comment, it is possible to simplify a lot the expression-SFINAE approach by removing completely the trait has_tip and simply forward to a little call helper.
The final code is really neat and tight !
#include <boost/tuple/tuple.hpp>
#include <boost/fusion/include/boost_tuple.hpp>
#include <boost/fusion/algorithm.hpp>
#include <iostream>
struct CallTip
{
template<typename T>
void operator()(const T& t) const
{
call(t);
}
template<class T>
static auto call(const T&) -> decltype(T::tip())
{
std::cout << "tip\n";
T::tip();
}
static void call(...)
{
std::cout << "no tip\n";
}
};
struct A {
static void tip(){}
};
struct B {
static void tip(){}
};
struct Z {
};
int main()
{
A a;
B b;
Z z;
boost::tuple<const A&,const B&,const Z&> tpl(a, b, z);
boost::fusion::for_each(tpl, CallTip());
}

Compile-Time Polymorphism for Data Members

In the following code, initialize() illustrates a method based on compile-time polymorphism. The version of initialize() compiled depends on int2type<true> and int2type<false>, only one of which will be true for a given template parameter T.
It just so happens that data member T* m_datum; will work for both int2type<true> and int2type<false>.
Now, I want to change the int2type<false> version to std::vector<T> m_datum;, so my question is, how do I modify my code so that the data member m_datum is polymorphic on int2type<>?
Note: please ignore the rationale behind the code below - instead, I would like to focus on the mechanics of achieving compile-time polymorphism for data members.
#include <type_traits>
#include <stdlib.h>
using namespace std;
template <bool n>
struct int2type
{
enum { value = n };
};
template< typename T >
struct is_trivially_copyable
{
static const bool value = std::is_standard_layout<T>::value;
};
template<class T>
class Foo
{
public:
Foo( size_t n ) : m_nr( n )
{
initialize( int2type<is_trivially_copyable<T>::value>() );
}
~Foo() { }
private:
void initialize( int2type<true> )
{
m_datum = (T*) calloc( sizeof(T), m_nr );
}
void initialize( int2type<false> )
{
m_datum = new T[m_nr];
}
private:
size_t m_nr;
T* m_datum; // ok for int2type<true>
// vector<T> m_datum; // want to change to this for int2type<false>
};
class Bar
{
public:
Bar() { }
virtual ~Bar() { }
};
int main(int argc, char** argv)
{
Foo<int> foo_trivial( 5 );
Foo<Bar> foo_nontrivial( 10 );
return 0;
}
C++11 solution, based on Nawaz's recommendations
#include <type_traits>
#include <vector>
#include <stdlib.h>
using namespace std;
template< typename T >
struct is_trivially_copyable
{
static const bool value = std::is_standard_layout<T>::value;
};
template<class T>
class Foo
{
private:
static const bool what = is_trivially_copyable<T>::value;
typedef typename std::conditional<what,T*,std::vector<T>>::type type;
public:
Foo( size_t n ) : m_nr( n )
{
initialize( m_datum );
}
~Foo() { }
private:
void initialize( T* dummy )
{
m_datum = (T*) calloc( sizeof(T), m_nr );
}
void initialize( std::vector<T>& dummy )
{
m_datum.resize( m_nr );
}
private:
size_t m_nr;
type m_datum;
};
class Bar
{
public:
Bar() { }
virtual ~Bar() { }
};
int main(int argc, char** argv)
{
Foo<int> foo_trivial( 5 );
Foo<Bar> foo_nontrivial( 10 );
return 0;
}
C++11 Solution
Use std::conditional as:
#include <type_traits>
template<class T>
class Foo
{
//some info we can use throughout the class
static const bool what = is_trivially_copyable<T>::value;
typedef typename std::conditional<what, T*, std::vector<T>>::type data_type;
//data members
data_type m_data; //this is what you need!
}
C++03 Solution
You can write a metafunction and partially specialize this as follows:
template<class T>
class Foo
{
//primary template
template<bool b, typename T>
struct get { typedef T* type; };
//partial specialization
template<typename T>
struct get<false, T> { typedef std::vector<T> type; };
//some info we can use throughout the class
static const bool what = is_trivially_copyable<T>::value;
typedef typename get<what, T>::type data_type;
//data members
data_type m_data; //this is what you need!
};
So when what is true, data_type will turn out to be T*, or else it will be std::vector<T>, as desired.
In either case, you don't need int2type class template. Just remove that from your code. You can write cleaner code, without it.
How about:
// Generic
template <typename T, typename Arg>
struct datum_type_dispatch {};
// Specialization for Arg = int2type<true>
template <typename T>
struct datum_type_dispatch<T, int2type<true> >
{
typedef T* type;
};
// Specialization for Arg = int2type<false>
template <typename T>
struct datum_type_dispatch<T, int2type<false> >
{
typedef std::vector<T> type;
};
template <typename T>
class Foo
{
// ...
private:
// Get the datum type based on int2type<...>
typedef typename datum_type_dispatch<T, int2type<is_trivially_copyable<T>::value> >::type datum_type;
datum_type m_datum;
};

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.