I've made a function that calculates the sine of a number. It returns the input type if it is std::is_floating_point
. But for std::is_integral
, it returns a double
.
template<class T , typename std::enable_if<std::is_integral<T>::value>::type* = nullptr >
double mysin(const T& t) // note, function signature is unmodified
{
double a = t;
return std::sin(a);
}
template<class T , typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr >
T mysin(const T& t) // note, function signature is unmodified
{
return std::sin(t);
}
Easy enough. Now I'd like this to work for vector
s (or arrays) and tuple
s (or clusters). So that:
(pseudo code:)
std::vector<std::double> a = mysin(std::vector<std::int>);
std::tuple<std::double, std::float> b = mysin(std::tuple<std::int, std::float>);
std::vector<std::tuple<std::double, std::float>> c = mysin(std::vector<std::tuple<std::int, std::float>>);
std::tuple<std::vector<std::double>, std::float> d = mysin(std::tuple<std::vector<std::int>, std::float>);
std::tuple<std::tuple<std::double, std::vector<std::double>>, std::float>> e = mysin(std::tuple<std::tuple<std::int, std::vector<std::int>>, std::float>>);
and so on...
In most examples about tuple
templates, the function either has no return value, returns an accumulated value, or has the same return type as the input.
I've experimented a lot with these topics (among others): Traversing nested C++11 tuple , c++11: building a std::tuple from a template function , How to make a function that zips two tuples in C++11 (STL)?
The last one has been especially useful. I've got this working for tuple
s, but not for recursive tuples
(tuple
s in tuple
s).
Eventually (if this is possible at all), I'll have to make a mycos
, mytan
, myasin
, etc. Using gcc 4.9.2.
**EDIT:**So this is what I came up with after Yakk's suggestions, and a little tweaking:
#include <utility>
#include <vector>
#include <memory>
#include <typeinfo> // used for typeid
#include <tuple>
#include <cstdlib> // for math functions?
#include <cmath> // for math functions
#include <type_traits> // for std::enable_if
template<class T , typename std::enable_if<std::is_integral<T>::value>::type* = nullptr >
double mysin(const T& t) { // note, function signature is unmodified
double a = t;
return std::sin(a);
// printing a debug string here will
// print tuple elements reversed!!
}
template<class T , typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr >
T mysin(const T& t) {// note, function signature is unmodified
// printing a debug string here will
// print tuple elements reversed!!
return std::sin(t);
}
struct sine_t {
template<class T>
auto operator()(T&&t)const->
decltype(mysin(std::declval<T>())) {
return mysin(std::forward<T>(t));
}
};
template<class F>
struct vectorize {
template<class T,
class R=std::vector< std::result_of_t< vectorize<F>(T const&) > >
>
R operator()( std::vector<T> const& v ) const {
R ret;
ret.reserve(v.size());
for( auto const& e : v ) {
ret.push_back( vectorize<F>{}(e) );
}
return ret;
}
template<
class X,
class R=std::result_of_t< F(X const&) >
>
R operator()( X const& x ) const {
return F{}(x);
}
template<
class R,
class... Ts,
size_t... Is
>
R tup_help( std::index_sequence<Is...>, std::tuple<Ts...> const& t ) const {
return std::make_tuple( vectorize<F>{}(std::get<Is>(t))... );
}
template<
class... Ts,
class R=std::tuple< std::result_of_t< vectorize<F>(Ts const&) >... >
>
R operator()( std::tuple<Ts...> const& t ) const {
return tup_help<R>( std::index_sequence_for<Ts...>{}, t );
}
};
//+++++++++++++++++++++++++++++++++++++++++
int main() {
std::vector<int> a = {1 ,2};
std::tuple<int, double, int, double> b (42, -3.14, 42, -3.14);
auto c = vectorize<sine_t>()(a);
auto d = vectorize<sine_t>()(b);
std::vector<std::tuple<int, int> > e {std::make_tuple(1 ,2)};
//This does not not work:
//auto f = vectorize<sine_t>()(e);
//This works:
std::tuple<std::vector<int> > g ( a );
auto f = vectorize<sine_t>()(g);
return 0;
}
This works. Needs c++14.