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! :-/
Related
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;
};
Let's imagine I have several template functions, e.g.:
template <int I> void f();
template <int I> void g();
template <int I> void h();
How can I call sequence of any of these functions for sequence of template parameters?
In other words, I need such behaviour:
{some template magic}<1, 5>(f); // This is pseudocode, I don't need exactly this format of calling.
unrolls into:
f<1>();
f<2>();
f<3>();
f<4>();
f<5>();
And I need the same method to work for every of my functions (not only for f, but for g and h too) without writing big awkward structure for every of these functions.
I can use C++11, and even already implemented in latest development gcc version C++1y/C++14 functionality (http://gcc.gnu.org/projects/cxx1y.html), e.g. polymorphic lambdas.
With C++1y features. Instead of calling the function directly and passing the template argument as, well, a template argument, you can create a lambda that takes a function argument which contains the template argument as part of its type. I.e.
f<42>();
[](std::integral_constant<int, 42> x) { f<x.value>(); }
[](auto x) { f<x.value>(); }
With this idea, we can pass the function template f around, when wrapped into such a polymorphic lambda. That's possible for any kind of overload set, one of the things you can't do with ordinary lambdas.
To call f with a sequence of template arguments, we'll need the common indices classes for the indices expansion trick. Those will be in the C++1y Standard Library. Coliru's clang++ compiler for example still uses an older libstdc++ which doesn't have them AFAIK. But we can write our own:
#include <utility>
using std::integral_constant;
using std::integer_sequence; // C++1y StdLib
using std::make_integer_sequence; // C++1y StdLib
// C++11 implementation of those two C++1y StdLib classes:
/*
template<class T, int...> struct integer_sequence {};
template<class T, int N, int... Is>
struct make_integer_sequence : make_integer_sequence<T, N-1, N-1, Is...> {};
template<class T, int... Is>
struct make_integer_sequence<T, 0, Is...> : integer_sequence<T, Is...> {};
*/
When we write make_integer_sequence<int, 5>, we'll get a type that's derived from integer_sequence<int, 0, 1, 2, 3, 4>. From the latter type, we can deduce the indices:
template<int... Indices> void example(integer_sequence<int, Indices...>);
Inside this function, we have access to the indices as a parameter pack. We'll use the indices to call the lamba / function object f as follows (not the function template f from the question):
f( integral_constant<int, Indices>{} )...
// i.e.
f( integral_constant<int, 0>{} ),
f( integral_constant<int, 1>{} ),
f( integral_constant<int, 2>{} ),
// and so on
Parameter packs can only be expanded in certain contexts. Typically, you'd expand the pack as initializers (e.g. of a dummy array), as the evaluation of those is are guaranteed to be ordered (thanks, Johannes Schaub). Instead of an array, one could use a class type such as
struct expand { constexpr expand(...) {} };
// usage:
expand { pattern... };
A dummy array looks like this:
int expand[] = { pattern... };
(void)expand; // silence compiler warning: `expand` not used
Another tricky part is to deal with functions returning void as the pattern. If we combine a function call with a comma operator, we always get a result
(f(argument), 0) // always has type int and value 0
To break any existing overloaded comma operators, add a void()
(f(argument), void(), 0)
Finally, combine all the above to create magic:
template<int beg, class F, int... Is>
constexpr void magic(F f, integer_sequence<int, Is...>)
{
int expand[] = { (f(integral_constant<int, beg+Is>{}), void(), 0)... };
(void)expand;
}
template<int beg, int end, class F>
constexpr auto magic(F f)
{
// v~~~~~~~v see below (*)
return magic<beg>(f, make_integer_sequence<int, end-beg+1>{});
}
Usage example:
#include <iostream>
template<int N> void f() { std::cout << N << "\n"; }
int main()
{
//magic<1, 5>( [](auto x) { f<decltype(x)::value>(); } );
magic<1, 5>( [](auto x) { f<x.value>(); } );
}
(*) IMHO end-beg+1 is bad practice. There's a reason why the StdLib works with half-open ranges of the form [begin, end): The empty range simply is [begin, begin). With the StdLib using half-open ranges, it might be inconsistent to use closed ranges here. (There's one exception in the StdLib I know of, it has to do with PRNGs and the maximum integer value.)
I'd suggest you'd design your magic interface to take half-open ranges, i.e.
magic<1, 6>( [](auto x) { f<x.value>(); } ); // [1, 6) i.e. {1,2,3,4,5}
with the implementation
template<int beg, int end, class F>
constexpr auto magic(F f)
{
// v~~~~~v
return magic<beg>(f, make_integer_sequence<int, end-beg>{});
}
Note the weird +1 disappears.
Using reified functions and template template arguments:
#include <iostream>
template<int I> class f {
public:
static void call() {
std::cout << I << '\n';
}
};
template<template<int I> class X, int I, int J> class magic {
public:
static void call() {
X<I>::call();
magic::call();
}
};
template<template<int I> class X, int I> class magic<X,I,I> {
public:
static void call() {
X<I>::call();
}
};
int main(int argc, char** argv) {
magic<f,2,6>::call();
return 0;
}
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.
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];
I have a template class with an overloaded + operator. This is working fine when I am adding two ints or two doubles. How do I get it to add and int and a double and return the double?
template <class T>
class TemplateTest
{
private:
T x;
public:
TemplateTest<T> operator+(const TemplateTest<T>& t1)const
{
return TemplateTest<T>(x + t1.x);
}
}
in my main function i have
void main()
{
TemplateTest intTt1 = TemplateTest<int>(2);
TemplateTest intTt2 = TemplateTest<int>(4);
TemplateTest doubleTt1 = TemplateTest<double>(2.1d);
TemplateTest doubleTt2 = TemplateTest<double>(2.5d);
std::cout << intTt1 + intTt2 << /n;
std::cout << doubleTt1 + doubleTt2 << /n;
}
I want to be able to also do this
std::cout << doubleTt1 + intTt2 << /n;
Stephen has already given a good explanation of the problems you may encounter with this. You can define overloads for all the possible combinations of all the instantiations of the template (so, you'd effectively have operators defined for double + double, int + double, double + int, etc.). This can get unwieldy fast and can be difficult to keep track of which combinations are supported.
You might be better off using a non-member function named something like Add(). The advantage of doing this is that you can specify the return type. The disadvantage is that you have to specify the return type. :-) In general, though, this is better than performing unexpected conversions automatically.
template <typename R, typename T, typename U>
TemplateTest<R> Add(const TemplateTest<T>& t, const TemplateTest<U>& u)
{
return TemplateTest<R>(t.x + u.x);
}
invoked as:
std::cout << Add<double>(intTt1, doubleTt1) << std::endl;
C++0x will add support for a number of language features that will make this much simpler and will allow you to write a reasonable operator+ overload:
template <typename T, typename U>
auto operator+(const TemplateTest<T>& t, const TemplateTest<U>& u)
-> TemplateTest<decltype(t.x + u.x)>
{
return TemplateTest<decltype(t.x + u.x)>(t.x + u.x);
}
This will ensure that the usual arithmetic conversions (integer promotion, conversion to floating point, etc.) are performed and you end up with the expected result type.
Your C++ implementation may support these C++0x features already; you'd want to consult the documentation of whatever compiler you are using.
Here be dragons. You're getting into parts of c++ that will probably result in a lot of questions posted to StackOverflow :) Think long and hard about if you really want to do this.
Start with the easy part, you want to allow operator+ to add types that are not always the same as T. Start with this:
template <typename T2>
TemplateTest<T> operator+(const TemplateTest<T2>& rhs) {
return TemplateTest<T>(this->x + rhs.x);
}
Note that this is templated on T2 as well as T. When adding doubleTt1 + intTt2, T will be doubleTt1 and T2 will be intTt2.
But here's the big problem with this whole approach.
Now, when you add a double and an int, what do you expect? 4 + 2.3 = 6.3? or 4 + 2.3 = 6? Who would expect 6? Your users should, because you're casting the double back to an int, thus losing the fractional part. Sometimes. Depending on which operand is first. If the user wrote 2.3 + 4, they would get (as expected?) 6.3. Confusing libraries make for sad users. How best to deal with that? I don't know.
I want to be able to also do this
std::cout << doubleTt1 + intTt2 << "\n";
What you'll probably need for this case are type traits. Basically, those are template classes containing typedefs. You then partially specialize such a template to override the typedefs.
Basic example:
(This is probably a bit naïve, but it should get the basic idea across.)
template <typename A, typename B>
struct add_traits
{
typedef A first_summand_t; // <-- (kind of an "identity type")
typedef B second_summand_t; // <-- (ditto; both aren't strictly necessary)
typedef B sum_t; // <-- this is the interesting one!
};
Now you partially specialize that thing for various combinations of A and B:
template<>
struct add_traits<int, int>
{
typedef int first_summand_t;
typedef int second_summand_t;
typedef int sum_t; // <-- overrides the general typedef
};
template<>
struct add_traits<int, double>
{
typedef int first_summand_t;
typedef double second_summand_t;
typedef double sum_t; // <-- overrides the general typedef
};
template<>
struct add_traits<double, int>
{
typedef double first_summand_t;
typedef int second_summand_t;
typedef double sum_t; // <-- overrides the general typedef
};
Now you could write a fairly generic add operation that went like this:
template <typename A, typename B>
typename add_traits<A,B>::sum_t add(A first_summand, B second_summand)
{
// ...
}
As you can see, you don't specify a concrete return type; instead, you let the compiler figure it out through the add_traits template class. Once the compiler generates the code for a particular add function, it will look up the types in the corresponding add_traits class, and thanks to the partially specialized versions that you provided, you can make sure that certain type "combinations" will be applied.
P.S.: The same technique would e.g. also be useful when you want to subtract unsigned numbers. One unsigned int subtracted from another can result in a negative answer; the result type would have to be a (signed) int.
P.P.S.: Corrections made according to the comments below.
The add operator should generally be a free function to avoid preferring any operand type as #Stephen nicely explains. This way it's completely symmetric. Assuming you have a function get that returns the stored value, this can be like the following (alternatively, you can declare it as a friend if such a get function does not exist)
template<typename T1, typename T2>
TemplateTest<???> operator+(const TemplateTest<T1>& t1, const TemplateTest<T2>& t2)
{
return TemplateTest<???>(t1.get() + t2.get());
}
The problem now is to find a result type. As other answers show this is possible with decltype in C++0x. You can also simulate this by using the rules of the ?: operator which are mostly quite intuitive. promote<> is a template that uses that technique
template<typename T1, typename T2>
TemplateTest< typename promote<T1, T2>::type >
operator+(const TemplateTest<T1>& t1, const TemplateTest<T2>& t2)
{
return TemplateTest< typename promote<T1, T2>::type >(t1.get() + t2.get());
}
Now for example if you add double and int, it will yield double as the result. Alternatively as shown in the promote<> answer, you can also specialize promote so you can apply it directly to TemplateTest types.
If this is mainly for basic types, you could help yourself with a metafunction until the new standard rolls in. Something along the lines of
template<typename T1,
typename T2,
bool T1_is_int = std::numeric_limits<T1>::is_integer,
bool T2_is_int = std::numeric_limits<T2>::is_integer,
bool T1_is_wider_than_T2 = (sizeof(T1) > sizeof(T2)) > struct map_type;
template<typename T1, typename T2, bool b> struct map_type<T1, T2, b, b, true > { typedef T1 type; };
template<typename T1, typename T2, bool b> struct map_type<T1, T2, b, b, false> { typedef T2 type; };
template<typename T1, typename T2, bool b> struct map_type<T1, T2, false, true , b> { typedef T1 type; };
template<typename T1, typename T2, bool b> struct map_type<T1, T2, true , false, b> { typedef T2 type; };
template<typename T, typename U>
typename map_type<TemplateTestT<T>, TemplateTest<U> >::type
operator+(TemplateTest<T> const &t, TemplateTest<U> const &u) {
return typename map_type<TemplateTest<T>, TemplateTest<U> >::type(x + t1.x);
}
Of course, this is best combined with the char_traits idea:
template <typename A, typename B>
struct add_traits
{
typedef A first_summand_t;
typedef B second_summand_t;
typedef typename map_type<A, B>::type sum_t;
};
So that you can still specialise for types that don't have a numeric_limits overload.
Oh, and in production code, you'll probably want to properly namespace that and add something for signed/unsigned mismatches in integer types.
Get a compiler that supports the new C++0x decltype operator.
template < typename T1, typename T2 >
auto add(T1 t1, T2 t2) -> decltype(t1+t2)
{
return t1 + t2;
}
Now you don't have to fart around with those "traits" classes.
You can add int and double values by using templates.In the function, specify 2 arguments and while passing values to the functions specify its types in angular brackets.
example:
//template
template<typename T1, typename T2>
void add(T1 a, T2 b)
{
//for adding values
cout<<"\n\nSum : "<<a+b;
}
int main ()
{
//specify types while passing values to funcion
add<int,double>(4,5.5454);
add<float,int>(4.7,5);
add<string,string>("hi","bye");
return 0;
}
Newer answer to an old question.
For C++0x you can go with decltype as other answers have talked about.
I would argue that common_type is more made for the situation than decltype.
Here is an example of common_type used in a generic add:
#include <iostream>
#include <array>
#include <type_traits>
using namespace std;
template <typename T, typename U, unsigned long N>
array<typename common_type<T, U>::type, N> // <- Gets the arithmetic promotion
add_arrays(array<T, N> u, array<U, N> v)
{
array<typename common_type<T, U>::type, N> result; // <- Used again here
for (unsigned long i = 0; i != N; ++i)
{
result[i] = u[i] + v[i];
}
return result;
}
int main()
{
auto result = add_arrays( array<int, 4> {1, 2, 3, 4},
array<double, 4> {1.0, 4.23, 8.99, 55.31} );
for (size_t i = 0; i != 4; ++i)
{
cout << result[i] << endl;
}
return 0;
}
it basically returns the value that different arithmetic operations would promote to. One nice thing about it is that it can take any number of template args. Note: don't forget to add the ::type at the end of it. That is what gets the actual type result that you want.
For those working pre-c++11 still, there is a boost version of common_type as well
This is technically possible by defining an implicit case to TemplateTest<double>:
operator TemplateTest<double>() {
return TemplateTest<double>((double)x);
}
Practically this probably isn't a great idea though, as x can't necessarily be safely cast to a double; it happens that you're using a TemplateTest<int> here, but you could be using a TemplateTest<std::string> later. You should probably rethink what you're doing and decide if you're sure you actually need this behavior