C++ template metafunction on instantiated object of a template class - c++

I hope that this question isn't overly convoluted. I realize that meta-programming acts on types rather than on the objects of those types; however, I am still trying to achieve the same result, by 1) retrieving the type information from the class and then 2) meta-functions on that type information.
An explanation of my situation is as follows with simplified code excerpts:
I have a template class for matrices, which I am calling Matrix_Base. Somewhat similar to the approach taken by Eigen, I am allowing for two possibilities for the size of a matrix -- either fixed at compile-time or fixed at run-time. Simplified declaration of Matrix_Base is:
template <typename Type, uint32_t rows_ = 1, uint32_t cols_ = 1,>
class Matrix_Base{
/*
...
*/
};
Run-time sized matrix is denoted by an argument of 0.
The check for run-time vs compile-time sizing of the matrix is fairly simple (using boost::mpl):
typedef typename mpl::if_<
typename mpl::or_<
typename mpl::equal_to<
typename mpl::int_<rows_>::type,
mpl::int_<0>
>::type,
typename mpl::equal_to <
typename mpl::int_<cols_>::type,
mpl::int_<0>
>
>::type,
mpl::true_,
mpl::false_
>::type runtime_size_type;
This has been tested and works fine. My trouble starts about here...
Presently, I am using the above boost::mpl code in the following manner:
namespace internal {
template <uint32_t rows = 1, uint32_t cols_ = 1>
struct Runtime_Size_Helper {
typedef typename mpl::if_<
// REST OF THE BOOST::MPL code here //
>::type runtime_size_t
bool value() { return runtime_size_t::value;}
};
} // namespace
template <typename Type, uint32_t rows_ = 1, uint32_t cols_ = 1>
class Matrix_Base{
// ...
static constexpr uint32_t rows = rows_;
static constexpr uint32_t cols = cols_;
bool is_runtime_sized;
// ...
};
template <typename T, uint32_t R, uint32_t C>
bool Matrix_Base<T,R,C>::is_runtime_sized = internal::Runtime_Size_Helper<R,C>::value();
This makes the result of that mpl function into a member of the Matrix_Base class. So far so good.
I'd like to use some form of indirection to determine the value of runtime_size_type by passing it the instantiated object. As per the example code, the only required information to determine this is the uint32_t parameters for col and row.
For the instantiated Matrix_Base object, the relevant information will never change from its compile-type values. The size of the matrix will be immutable; the size will either be set from the template arguments or -- for runtime-sized matrices -- through the constructor. In both cases, the template arguments are fixed and part of the type information. I am saving this information as static variables in the class, and I have even tried to add a typedef with all of the template parameters as my_type typename typename Matrix_Base<T,rows_, cols_, ...> my_type but I cannot seem to figure out how to write a metafunction to which I can pass a Matrix_Base object (obviously as a reference or pointer) and re-extract the relevant information.
I am fully open to incorporating (other) boost libraries, if they would provide the necessary functionality.
Hope that this is clear. Please let me know if there's something here that's unclear or that's just plain stupid.
Best regards,
Shmuel
edited the text to provide a bit more clarity as to the issue

The quickest way to do what you seem to want (you didn't really specify it in detail) is to let your matrix class template inherit from a storage class template, and to specialize the storage class depending on whether your MPL predicate returns true or false
#include <array>
#include <iostream>
#include <vector>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/comparison.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/logical.hpp>
using namespace boost;
// in C++98, use
// template<int R, int C>
// struct is_runtime_sized: mpl::if<
// ...
// >::type {};
template<int R, int C>
using is_runtime_sized = typename mpl::if_<
mpl::or_<
mpl::equal_to<mpl::int_<R>, mpl::int_<0>>,
mpl::equal_to<mpl::int_<C>, mpl::int_<0>>
>,
mpl::true_, mpl::false_
>::type;
Note that I've eleminated some unnecessary typename occurances to make the MPL predicate more readable.
template<class T, int R, int C, bool = is_runtime_sized<R, C>::value>
struct MatrixStorage
{
MatrixStorage() = default;
MatrixStorage(int r, int c): data_(r * c) {} // zero-initializes
protected:
std::vector<T> data_;
};
template<class T, int R, int C>
struct MatrixStorage<T, R, C, false>
{
MatrixStorage() = default;
MatrixStorage(int, int): data_{} {} // zero-initializes
protected:
std::array<T, R * C> data_;
};
Here, I've split the implementation of the dynamically and statically stored matrices. The former uses a std::vector and the latter a std:array. Similar to Eigen, both have a default constructor, and both also have a constructor taking the matrix dimensions that zero-initializes.
template<class T, int R = 0, int C = 0>
struct Matrix: public MatrixStorage<T, R, C>
{
Matrix() = default;
// In C++98, write:
// Matrix(int r, int c): MatrixStorage<T, R, C>(r, c) {}
using MatrixStorage<T, R, C>::MatrixStorage;
int size() const { return this->data_.size(); }
};
The actual Matrix class inherits from the MatrixStorage, and returns a size() depending on the currently stored data.
int main()
{
Matrix<int> m_dyn(3, 3);
std::cout << m_dyn.size() << "\n"; // 9
Matrix<int, 2, 2> m_stat;
std::cout << m_stat.size() << "\n"; // 4
}
Live Example. As you can see, the dynamically allocated matrix has size 9, and the statically sized one has size 4. Note that there are two small C++11 features in the above code, that you can easily work-around if you are required to use C++11.

Related

How do I get access to template parameters of a template pack parameter

I am trying to create a template class that will enable a compare function to return an integer [ 0 - equal, >0 a should come first, <0 b should come first ].
I am using Sort structs template parameters to keep track of the type that should be used, offset of the field in the string, as well as the order that this field should be kept... so compare can according return the correct value.
Assume for now that the std::string is used to represent a serialized value.
I am having trouble with extracting the information from the template. I have kept sort as a pack parameter, which would be of the type Sort. How do I access these parameters in the code? If there is a better way to refactor this. I looked at some of the other questions related to templates, but didn't see any that would solve this problem. I am using gcc 8.2 and c++17.
#include <cstdint>
#include <string>
#include <cstring>
#include <cassert>
template<typename T, uint32_t offset, char Order = 'A'>
struct Sort {};
template<uint32_t keyLength, template<typename T,uint32_t offset, char Order> class ... sort>
class Comparator {
public:
int compare(std::string & a, std::string &b) {
assert(a.length()==b.length());
// How would I sum the sizeof each T. i.e. if T is int and another T is short, then sum should be 6+keyLength?
assert(a.length()==(sizeof(T)+keyLength)); // Check that my length is equal to key length + all type lengths put together
auto r = memcmp(a.data(),b.data(),keyLength);
if(r!=0) return r;
// How do I retrieve T,offset,Order of each pack parameter.
return internal_compare<T,offset,Order>(a.data(),b.data())? internal_compare<T,offset,Order>(a.data(),b.data()) : ...;
}
private:
template<typename IT,uint32_t iOffset, char iOrder>
int internal_compare(char * a,char *b) {
if constexpr (iOrder=='A'||iOrder=='a') {
return (*(static_cast<IT *>(a+iOffset)))-(*(static_cast<IT *>(b+iOffset)));
} else {
return (*(static_cast<IT *>(b+iOffset)))-(*(static_cast<IT *>(a+iOffset)));
}
}
};
Two things I have not been able to accomplish.
One is getting the sum of sizeof(T) from the sort.
Call the internal compare operator on each sort.
Link to code on compiler explorer
This becomes substantially easier if instead of using this form:
template<typename T, uint32_t offset, char Order = 'A'>
struct Sort {};
template<uint32_t keyLength, template<typename T,uint32_t offset, char Order> class ... sort>
class Comparator;
You use this one:
template <uint32_t keyLength, class...>
class Comparator;
template <uint32_t keyLength, typename... T, uint32_t... offset, char... Order>
class Comparator<keyLength, Sort<T, offset, Order>...> {
// ...
};
First, the original didn't do what you wanted to do anyway. You wanted specific instantiations of Sort but you were actually accepting class templates... like Comparator<32, Sort, Sort, Sort>. Which presumably isn't meaningful.
But when we do it this way, we're not only accepting only instantiations of Sort but we have the parameters in the most useful form. So something like this:
// How would I sum the sizeof each T. i.e. if T is int and another T is short,
// then sum should be 6+keyLength?
Is a fold-expression:
(sizeof(T) + ... + keyLength)
And so forth.
I'll take this problem on another front: how do you extract the template parameters if T has template parameters? Here's an example:
template<typename T>
void foo(T v) {
// T is std::vector<int>, how to extract `int`?
}
int main() {
foo(std::vector{1, 2, 3, 4});
}
There's many answers to that: extraction using partial specialization, type aliases and others.
Here's how you can do it for std::vector:
template<typename>
struct extract_value_type_t {};
template<typename T>
struct extract_value_type_t<std::vector<T>> {
using type = T;
};
template<typename T>
using extract_value_type_t = typename extract_value_type<T>::type;
template<typename T>
void foo(T v) {
// with template specialization
using value_type = extract_value_type_t<T>;
// with the member alias std::vector exposes
// needs much less boilerplate!
using value_type = typename T::value_type;
}
What does doing it with T when it's a vector gives us? Well, if you can do something with a simple type T, you won't even need a template template parameter, making your interface more flexible:
template<typename>
struct sort_traits {};
template<typename T, uint32_t offset_, char order_>
struct sort_traits<Sort<T, offset_, order_>> {
using type = T
static constexpr auto offset = offset_;
static constexpr auto order = order_;
};
Then in your Comparator class, simply do something like that:
template<uint32_t keyLength, typename... sorts>
struct Comparator {
int compare(std::string const& a, std::string const& b) {
return (internal_compare<sorts>(a.data(), b.data()) && ...);
}
private:
template<typename sort>
int internal_compare(char const* a, char const* b) {
using traits = sort_traits<sort>;
using type = typename traits::type;
constexpr auto offset = traits::offset;
constexpr auto order = traits::order;
// do stuff
}
};
This also add the possibility one day to add another kind of sort that would have different template parameters or different things exposed.

Boost MPL Sorting Template Parameter Pack

The problem I'm trying to solve is to sort a template parameter pack according to the return value of a constexpr templated function specialized for each of the types I'm sorting.
I have a list of approximately 100 BOOST_STRONG_TYPEDEFs which creates types TYPE_1, TYPE_2, ..., TYPE_N.
BOOST_STRONG_TYPEDEF(TYPE_1, int)
BOOST_STRONG_TYPEDEF(TYPE_2, double)
// et cetera
BOOST_STRONG_TYPEDEF(TYPE_N, uint8_t)
Then I declare a general template constexpr size_t value_of() for which I specialize for each one of my types:
template<> constexpr size_t value_of<TYPE_1>() { return 1; }
template<> constexpr size_t value_of<TYPE_2>() { return 2; }
// et cetera
template<> constexpr size_t value_of<TYPE_N>() { return n; }
Then I have a class declared as follows. I need to sort each of the types in the UnsortedTypes parameter pack according to the result of value_of.
template<typename ...UnsortedTypes>
class MyClass {
typedef boost::mpl::vector<UnsortedTypes...> UnsortedTypeVector;
typedef typename boost::mpl::sort<
UnsortedTypeVector,
boost::mpl::less<
boost::mpl::size_t<value_of<boost::mpl::placeholders::_1>()>,
boost::mpl::size_t<value_of<boost::mpl::placeholders::_2>()>
>
>::type SortedTypes;
// Utility
void print_types() {
__print_types<SortedTypes>();
}
template<typename Type, typename ...Types>
void __print_types() {
std::cout << typeid(Type).name() << "\n";
if constexpr (sizeof...(Types) > 0) __print_types<Types...>();
}
};
When I test it out as follows:
int main(int, char *[]) {
MyClass<TYPE_5, TYPE_3, TYPE_4, TYPE_2, TYPE_1> myclass;
myclass.print_types();
}
I get this huge, pretty much unintelligible error message which seems to consist of errors within the mpl library.
Intuitively, I have a suspicion that this results from an incorrect definition of my sorting predicate. However, I'm not sure how to fix it!
(This is my first time using Boost.MPL and there aren't many examples online, so please be gentle!)
Here's a reduced example that might make it more obvious what's going on:
namespace mpl = boost::mpl;
template <typename T> constexpr size_t value_of() { return sizeof(T); }
template <typename... Ts>
struct X {
using V = mpl::vector<Ts...>;
using sorted = typename mpl::sort<
V,
mpl::less<
mpl::size_t<value_of<mpl::_1>()>,
// ~~~~~~~~~~~~~~~~~~~
mpl::size_t<value_of<mpl::_2>()>
>
>::type;
};
Now, you intended that this delays the invocation of value_of() until _1 is substituted into. But actually what happens is that it's invoked immediately - because that's what you're asking for. In my case, that's whatever sizeof(_1) ends up being. And so, since these are all constants, the full mpl::less<...> is just some integral constant expression - rather than being a lambda expression, like you wanted it to be.
What you need to do is ensure that invocation is delayed by turning your predicate into a metafunction:
template <typename T>
struct value_of_ : mpl::size_t<sizeof(T)> { };
And then you can use:
template <typename... Ts>
struct X {
using V = mpl::vector<Ts...>;
using sorted = typename mpl::sort<
V,
mpl::less<value_of_<mpl::_1>, value_of_<mpl::_2>>
>::type;
};

Partial specialization and SFINAE

Suppose I have the following Matrix template class and there is a requirement to represent vector as either 1 x RowSize or ColSize x 1 matrix (so that I can reuse many matrix operators which are compatible with vectors: multiplying 2 matrices, multiplying matrix by a scalar etc):
template <class T, size_t ColumnSize, size_t RowSize>
struct Matrix {
T [ColumnSize][RowSize];
}
I have two questions:
1) If I am not mistaken I can achieve that either by partial specialization or using SFINAE on Matrix methods (for example to enable 'length' method when either ColSize or RowSize is 1). What are the pros and cons of mentioned options?
2) If I choose to go with the partial specialization, is there a way to define one specialization for both row and column vectors, instead of this:
template <class T, size_t ColumnSize>
struct Matrix<T, ColumnSize, 1> {
T length() const;
T [ColumnSize][RowSize];
}
template <class T, size_t RowSize>
struct Matrix<T, 1, RowSize> {
T length() const;
T [ColumnSize][RowSize];
}
It really depends on whether the requirement is "a general Matrix must not have a length method" (then SFINAE or inheritance should be used), or "length must not be called on a general Matrix" (then a static_assert inside of the length body is applicable). A third option is to not do anything and make length applicable on generic matrices, however there are still other operations that only work on vectors.
For "a general Matrix must not have a length method". To save space, I will use int, and shorter symbol names. Instead of int_, you should use std::integral_constant. The int_ wrapper is needed because of language restrictions that forbid specializing with more complex computations if the parameter is a non-type parameter. Therefore we ḿake the paramer a type, and wrap the value into it. The following does not use SFINAE, but inheritance. With d() of the vector mixing base class, you can access the data of the vector at any time from within the mixing class.
template<int> struct int_;
template<typename D, typename S>
struct V { };
template<typename T, int A, int B>
struct M : V<M<T, A, B>, int_<A * B>> {
T data[A][B];
};
template<typename T, int A, int B>
struct V<M<T, A, B>, int_<A + B - 1>> {
int length() const { return A * B; }
M<T, A, B> *d() { return static_cast<M<T, A, B>*>(this); }
const M<T, A, B> *d() const { return static_cast<const M<T, A, B>*>(this); }
};
This is now
int main() {
M<float, 1, 3> m1; m1.length();
M<float, 3, 1> m2; m2.length();
// M<float, 3, 2> m3; m3.length(); error
}
For "length must not be called on a general Matrix", you can use "static_assert"
template<typename T, int A, int B>
struct M {
int length() const {
static_assert(A == 1 || B == 1, "must not be called on a matrix!");
return A * B;
}
T data[A][B];
};
Choose what is most appropriate
SFINAE is only able to disable a template declaration based on its own parameters. It's a bit unnatural to disable a non-template member function such as length, using the parameters of the enclosing class. The technique looks like this:
template <class T, size_t RowSize, size_t ColumnSize>
struct Matrix {
// SFINAE turns a non-template into a template.
// Introduce a fake dependency so enable_if resolves upon function call.
template< typename size_t_ = size_t >
static constexpr
// Now write the actual condition within the return type.
std::enable_if_t< RowSize == 1 || ColumnSize == 1
, size_t_ > length() const;
{ return RowSize * ColumnSize; }
T [ColumnSize][RowSize];
}
If you can stomach this ugliness, then you get exactly what you want: a function of the desired type, which completely vanishes when the condition is not met. No other support is needed.
On the other hand, partial specialization affects the entire class definition. Since it's usually poor design to duplicate the entire class in each partial specialization, inheritance is used as Johannes describes.
Just to add one alternative to his answer, SFINAE can be used within partial specialization, to avoid the clever algebra and the int_ issue.
// Add "typename = void" for idiomatic class SFINAE.
template<size_t RowSize, size_t ColumnSize, typename = void>
struct maybe_vector_interface { }; // Trivial specialization for non-vectors
// Partial specialization for vectors:
template<size_t RowSize, size_t ColumnSize>
struct maybe_vector_interface< RowSize, ColumnSize,
std::enable_if_t< RowSize == 1 || ColumnSize == 1 > > {
static constexpr int length() const
{ return RowSize * ColumnSize; }
};
template<typename T, size_t RowSize, size_t ColumnSize>
struct Matrix
: maybe_vector_interface<RowSize, ColumnSize> {
T data[RowSize][ColumnSize];
};

Static for cycle

I am writing templated short vector and small matrix classes, that are not restricted to having 2-3-4 elements, but can have an arbitrary number of elements.
template <typename T, size_t N>
class ShortVector
{
public:
...
template <size_t I> T& get() { return m_data[I]; }
template <size_t I> const T& get() const { return m_data[I]; }
private:
T m_data[N];
};
I want to have the access interface be static, so that I can specialize the class to use built-in vector registers for the supported sizes of the class. (May them be AVX, C++AMP or OpenCL vectors.) Problem is that writing ALL the desirable operators for this class (unary-, +, -, *, /, dot, length, ...) requires an awful lot of template recursion, and I haven't even gotten to implement matrix-vector and matrix-matrix multiplication, where I will need nested recursion.
Right now I have non-member friend operators and a private member class with various static functions such as
template <size_t I, typename T1, typename T2> struct Helpers
{
static void add(ShortVector& dst, const ShortVector<T1, N>& lhs, const ShortVector<T2, N>& rhs)
{
dst.get<I>() = lhs.get<I>() + rhs.get<I>();
Helpers<I - 1, T1, T2>::add(dst, lhs, rhs);
}
...
};
template <typename T1, typename T2> struct Helpers < 0, T1, T2 >
{
static void add(ShortVector& dst, const ShortVector<T1, N>& lhs, const ShortVector<T2, N>& rhs)
{
dst.get<0>() = lhs.get<0>() + rhs.get<0>();
}
...
};
Writing static functions and specializations like this for all operators just feels wrong. Writing the more complex operations in this manner is highly error prone. What I'm looking for is something like
static_for< /*Whatever's needed to define something like a run-time for cycle*/, template <size_t I, typename... Args> class Functor>();
Or practically anything that let's me omit the majority of this boilerplate code. I have started writing such a class, but I could not get it to compile with a reasonable specialization. I feel I still lack the skill to write such a class (or function). I have looked at other libs such as Boost MPL, but have not fully committed to using it. I have also looked at std::index_sequence which might also prove useful.
While the std::index_sequence seems like the most portable solution, it has a major flaw I am reluctant to look over. Ultimately these classes must be SYCL compatible, meaning I am restricted to using C++11, including template metaprogramming techniques. std::integer_sequence is a C++14 STL library addition, and while this restriction of language standard only matters in terms of language features, nothing prevents the STL implementer to use C++14 language features while implementing a C++14 STL feature, therefore using C++14 STL features might not be portable.
I am open to suggestions, or even solutions.
EDIT
Here is what I'v come up so far. This is the header of Template Metaprogramming tricks I started to collect, and the for loop would be next in line. The helper needs a functor which has the running index as it's first parameter, and accepts various predicates. It would keep instantiating the functor as long as the predicate for the next iteration holds true. It would be possible to have the running index increment by any number, be multiplied by a number, etc.
You could have a look at Boost Fusion's algorithms.
All that's required is to adapt your type as a Fusion Sequence.
Simple sample: Live On Coliru
#include <boost/array.hpp>
#include <boost/fusion/adapted.hpp>
#include <boost/fusion/algorithm.hpp>
#include <boost/fusion/include/io.hpp>
#include <iostream>
int main()
{
using namespace boost;
boost::array<int, 4> iv4 { 1,2,3,4 };
boost::array<double, 4> id4 { .1, .2, .3, .4 };
auto r = fusion::transform(iv4, id4, [](auto a, auto b) { return a+b; });
std::cout << r;
}
Prints:
(1.1 2.2 3.3 4.4)
What about this:
template <size_t I, typename Functor, typename = std::make_index_sequence<I>>
struct Apply;
template <size_t I, typename Functor, std::size_t... Indices>
struct Apply<I, Functor, std::index_sequence<Indices...>> :
private std::tuple<Functor> // For EBO with functors
{
Apply(Functor f) : std::tuple<Functor>(f) {}
Apply() = default;
template <typename InputRange1, typename InputRange2, typename OutputRange>
void operator()(OutputRange& dst,
const InputRange1& lhs, const InputRange2& rhs) const
{
(void)std::initializer_list<int>
{ (dst.get<Indices>() = std::get<0>(*this)(lhs.get<Indices>(),
rhs.get<Indices>()), 0)... };
}
};
Usage could be
Apply<4,std::plus<>>()(dest, lhs, rhs); // Size or functor type
// can be deduced if desired
A (slightly modified) example: Demo.
You could also remove the functor state if it hinders you in any way:
template <size_t I, typename Functor, typename = std::make_index_sequence<I>>
struct Apply;
template <size_t I, typename Functor, std::size_t... Indices>
struct Apply<I, Functor, std::index_sequence<Indices...>>
{
template <typename InputRange1, typename InputRange2, typename OutputRange>
void operator()(OutputRange& dst,
const InputRange1& lhs, const InputRange2& rhs) const
{
(void)std::initializer_list<int>
{ (dst.get<Indices>() = Functor()(lhs.get<Indices>(),
rhs.get<Indices>()), 0)... };
}
};
Regarding
” I am restricted to using C++11, including template metaprogramming techniques. std::integer_sequence is a C++14 STL library addition […]
… you can do this with e.g. the g++ compiler:
namespace my {
using std::tuple;
using std::tuple_cat;
template< int i >
struct Number_as_type_ {};
template< int... values >
using Int_sequence_ = tuple< Number_as_type_<values>... >;
template< class Int_seq_a, class Int_seq_b >
using Concat_ = decltype( tuple_cat( Int_seq_a(), Int_seq_b() ) );
template< int max_index >
struct Index_sequence_t_
{
using T = Concat_<
typename Index_sequence_t_<max_index-1>::T, Int_sequence_<max_index>
>;
};
template<>
struct Index_sequence_t_<0> { using T = Int_sequence_<0>; };
template< int n_indices >
using Index_sequence_ = typename Index_sequence_t_<n_indices - 1>::T;
} // namespace my
Unfortunately Visual C++ 12.0 (2013) chokes on template argument deduction for the above Int_sequence_. Apparently it has to do with erroneously treating a templated using as a kind automatically referenced local typedef in a class. Anyway, working with that understanding of the Visual C++ compiler bug I rewrote the above as follows, which appears to work nicely also with Visual C++:
A version that works better with Visual C++ 12.0
namespace my {
using std::tuple;
using std::tuple_cat;
template< int i >
struct Number_as_type_ {};
template< int... values >
struct Int_sequence_
{
using As_tuple = tuple< Number_as_type_<values>... >;
};
template< int... values >
auto int_seq_from( tuple< Number_as_type_<values>... > )
-> Int_sequence_< values... >;
template< class Int_seq_a, class Int_seq_b >
using Concat_ = decltype(
int_seq_from( tuple_cat(
typename Int_seq_a::As_tuple(), typename Int_seq_b::As_tuple()
) )
);
template< int n_indices >
struct Index_sequence_t_
{
using T = Concat_<
typename Index_sequence_t_<n_indices-1>::T, Int_sequence_<n_indices-1>
>;
};
template<>
struct Index_sequence_t_<1> { using T = Int_sequence_<0>; };
template< int n_indices >
using Index_sequence_ = typename Index_sequence_t_<n_indices>::T;
} // namespace my
With the above C++11-based support available, a general compile time indexing for loop, or, if you will, template-based loop unrolling, can be implemented in C++11, so that code like this can be written:
template< int i >
struct Add_
{
void operator()( int sum[], int const a[], int const b[] ) const
{
sum[i] = a[i] + b[i];
}
};
#include <iostream>
using namespace std;
auto main() -> int
{
int sum[5];
int const a[] = {1, 2, 3, 4, 5};
int const b[] = {100, 200, 300, 400, 500};
my::for_each_index<5, Add_>( sum, a, b );
for( int x: sum ) { cout << x << ' '; } cout << endl;
}
Do note, however, that while this may appear to be the next best thing since sliced pizza, I suspect that any reasonably good compiler will do loop unrolling optimizations as a matter of course, i.e. that there is not necessarily any advantage to be gained from introducing this bit of extra complexity.
As always with respect to optimizations, do MEASURE.
This design does total loop unrolling, that is, instead of n executions of a loop body with varying index you get n instances of the loop body with different index values. It's not necessarily the best approach, e.g. since larger code has less chance of fitting in a cache (repeat: for optimizations always measure), and for parallelism you may have special requirements. You can check out “Duff’s device” for a technique for more limited loop unrolling.
namespace my {
using std::forward;
using std::initializer_list;
template< class Type >
void evaluate( initializer_list< Type > const& ) {}
namespace impl {
template< template <int> class Functor_, class... Args >
struct Call_with_numbers_
{
template< int... numbers >
void operator()( Int_sequence_<numbers...> const&, Args&&... args ) const
{
evaluate( {(Functor_<numbers>()( args... ), 0)...} );
}
};
} // namespace impl
template< int n, template<int> class Functor_, class... Args >
void for_each_index( Args&&... args )
{
using Seq = Index_sequence_<n>;
Seq s;
impl::Call_with_numbers_< Functor_, Args... >()( s, forward<Args>( args )... );
}
} // namespace my
Disclaimer: coded up late at night, so not necessarily very perfect! :-/

How do I access a Tuple like an Array (with bracket overload and type safety)?

I am trying to build a Tuple class that can be accessed like an Array. I could probably turn things into (void *) but that would defeat the purpose of the templates since I'm trying to get type-safety.
I'm compiling using VS2010 pro. My current non-working solution produces the following error.
Error: 'Item &MyList::operator ' : could not deduce template argument for 'N'.
#include <tuple>
#include <stdio.h>
template <int size, typename Ty0,
typename Ty1=std::tr1::_Nil, typename Ty2=std::tr1::_Nil, typename Ty3=std::tr1::_Nil,
typename Ty4=std::tr1::_Nil, typename Ty5=std::tr1::_Nil, typename Ty6=std::tr1::_Nil,
typename Ty7=std::tr1::_Nil, typename Ty8=std::tr1::_Nil, typename Ty9=std::tr1::_Nil>
struct MyList {
std::tuple<Ty0, Ty1, Ty2, Ty3, Ty4, Ty5, Ty6, Ty7, Ty8, Ty9> items;
template <int N, typename Ty>
Ty &operator[](int N) {
auto &var = std::get<N>(items);
return var;
}
};
void main() {
MyList<2, int, double> list;
auto var = list[0];
}
Potential Solutions: (edit)
Variadic templates with homogeneous data
Using constexpr C++11
It depends what you want to index the tuple with. If you're using a runtime integer then clearly you can't attain type safety; there's no way for the compiler to know what type to return (other in the case where the tuple is homogeneous, for which see above).
If on the other hand you're just after the syntax of subscripting, you can do this using indexing objects with appropriate types, e.g. (for exposition) the ready-made std::placeholders:
template<typename T>
typename std::tuple_element<std::is_placeholder<T>::value,
std::tuple<Ty0, Ty1, Ty2, Ty3, Ty4, Ty5, Ty6, Ty7, Ty8, Ty9>>::type &
operator[](T) { return std::get<std::is_placeholder<T>::value>(items); }
Usage:
using namespace std::placeholders;
auto var = list[_1];