I have a function with two template arguments, one for a vector data type (int, float, double, etc.) and one for an integer type (int, int16_t, uint32_t, etc.):
template <typename T, typename I>
void
add(std::vector<T> array, std::vector<I> idx) {
// ...
}
For tests, I would now like to loop over every possible combination of data/integer types, e.g.,
// pseudo code
for I in [int, int16_t, int32_t, ...] {
for T in [float, double, int, int16_t, ...] {
// create arguments a, b
add<T, I>(a, b);
}
}
Is it possible to loop over types at all? How?
There may be simpler ways to do this, but I would use the boost hana library, as follows:
#include <boost/hana/for_each.hpp>
#include <boost/hana/tuple.hpp>
#include <vector>
#include <iostream>
#include <boost/type_index.hpp>
namespace hana = boost::hana;
// for example's sake, just print the type
template <typename T, typename I>
void add(std::vector<T> array, std::vector<I> idx) {
using namespace boost::typeindex;
std::cout << type_id<T>().pretty_name() << " - " << type_id<I>().pretty_name() << std::endl;
}
int main() {
auto types1 = hana::tuple_t<int, int16_t, int32_t>;
auto types2 = hana::tuple_t<float, double, int, int16_t>;
hana::for_each(types1, [types2](auto t1) {
hana::for_each(types2, [t1](auto t2) {
using t1_type = typename decltype(t1)::type;
using t2_type = typename decltype(t2)::type;
add<t1_type, t2_type>({}, {});
});
});
}
If you have boost at hand then boost::hana is definitely the way to go. However, it's not very hard to reimplement that feature by hand if you have to:
#include <iostream>
template<typename... T>
struct iterator {
template<typename CB_T>
static void iterate(CB_T const& ) {}
};
template<typename first, typename... rest>
struct iterator<first, rest...> {
template<typename CB_T>
static void iterate(CB_T const& cb) {
cb(first());
iterator<rest...>::iterate(cb);
}
};
int main() {
iterator<int, float>::iterate([](auto const & v_1){
using v_1_t = decltype(v_1);
iterator<char, double>::iterate([&](auto const & v_2){
using v_2_t = decltype(v_2);
std::cout << typeid(v_1_t).name() << " vs " << typeid(v_2_t).name() << "\n";
});
});
return 0;
}
Related
This is the extraction of a follow-up question to this answer.
Given the following "loop" technique
#pragma once
// loop.hpp
#include <type_traits>
#include <utility>
template<std::size_t... indices, class LoopBody>
void loop_impl(std::index_sequence<indices...>, LoopBody&& loop_body) {
(// C++17's fold expression
loop_body(std::integral_constant<std::size_t, indices>{}),
...
);
}
template<std::size_t N, class LoopBody>
void loop(std::integral_constant<std::size_t, N>, LoopBody&& loop_body) {
loop_impl(std::make_index_sequence<N>{}, std::forward<LoopBody>(loop_body));
}
it is possible to iterate over a type list like this:
#include <iostream>
#include <string_view>
#include <tuple>
#include "loop.hpp"
template<class T>
std::string_view inspect() {
return __PRETTY_FUNCTION__;
}
using Types = std::tuple<int, int, char, bool, double>;
int main() {
loop(std::tuple_size<Types>{}, [&] (auto i) {
using T = std::tuple_element_t<i, Types>;
std::cout << i << ": " << inspect<T>() << "\n";
});
}
... but how to iterate over a list of templates?
Using Boost.Mp11, the first version is:
static constexpr auto size = std::tuple_size_v<Types>;
mp_for_each<mp_iota_c<size>>([&] (auto i) {
/* ... */
});
Doing this over templates works basically the same way:
using list = mp_list<mp_quote<std::tuple>, mp_quote<std::pair>>;
mp_for_each<list>([&](auto f){
// v is a tuple<int, char> the first time around and a pair<int, char>
// the second time around
mp_invoke_q<decltype(f), int, char> v;
});
Of course you can do whatever you want with f in the body, I just invoked it as an example of mp_quote and how well integrated it is with the rest of Mp11.
You may wrap templates of the form template<class...> class into a tag type like the following:
#pragma once
// template_tag.hpp
#include <tuple>
#include <type_traits>
template<
template<class...>
class Tmpl_
>
struct TemplateTag {
template<class... Ts>
using insert = Tmpl_<Ts...>;
template<
template<template<class... > class>
class TmplTmpl
>
using rewrap_into = TmplTmpl<Tmpl_>;
};
// convenience helper
template<class TmplTag, class... Ts>
using InsertTemplateArgs = typename TmplTag::template insert<Ts...>;
static_assert(
std::is_same<
InsertTemplateArgs< TemplateTag<std::tuple>, int, bool >,
std::tuple<int, bool>
>{}
);
// convenience helper
template<class TmplTag, template<template<class...> class> class TmplTmpl>
using RewrapTemplateInto = typename TmplTag::template rewrap_into<TmplTmpl>;
template<template<class...> class Tmpl>
struct OtherTemplateTag {};
static_assert(
std::is_same<
RewrapTemplateInto< TemplateTag<std::tuple>, OtherTemplateTag >,
OtherTemplateTag<std::tuple>
>{}
);
Once your templates are wrapped into a tag type, you can iterate over the types as before:
#include <iostream>
#include <string_view>
#include <tuple>
#include <utility>
#include <variant>
#include "loop.hpp"
#include "template_tag.hpp"
template<class T>
std::string_view inspect() {
return __PRETTY_FUNCTION__;
}
using Templates = std::tuple<
TemplateTag<std::tuple>,
TemplateTag<std::tuple>,
TemplateTag<std::pair>,
TemplateTag<std::variant>
>;
template<
template<class...>
class Tmpl
>
struct AnotherTemplateTag {};
int main() {
loop(std::tuple_size<Templates>{}, [&] (auto i) {
using TmplTag = std::tuple_element_t<i, Templates>;
std::cout << i << ": " << inspect<TmplTag>() << "\n";
using AnotherTmplTag = RewrapTemplateInto<TmplTag, AnotherTemplateTag>;
std::cout << " " << inspect<AnotherTmplTag>() << "\n";
using TmplWithArgs = InsertTemplateArgs<TmplTag, int, long>;
std::cout << " " << inspect<TmplWithArgs>() << "\n";
});
}
In the below code, the compiler can't figure out which constructor I want to use. Why, and how do I fix this? (Live example)
#include <tuple>
#include <functional>
#include <iostream>
template<typename data_type, typename eval_type, typename Type1, typename Type2>
class A
{
public:
using a_type = std::tuple<Type1, Type2>;
using b_type = std::tuple<std::size_t,std::size_t>;
inline explicit constexpr A(const std::function<data_type(a_type)>& Initializer,
const std::function<eval_type(data_type)>& Evaluator,
const Type1& elem1, const Type2& elem2)
{
std::cout << "idx_type" << std::endl;
}
inline explicit constexpr A(const std::function<data_type(b_type)>& Initializer,
const std::function<eval_type(data_type)>& Evaluator,
const Type1& elem1, const Type2& elem2)
{
std::cout << "point_type" << std::endl;
}
};
int main()
{
int a = 1;
long long b = 2;
auto c = A<double, double, long long, int>{
[](std::tuple<long long,int> p)->double { return 1.0*std::get<0>(p) / std::get<1>(p); },
[](double d)->double { return d; }, b,a
};
return 0;
}
The reason it doesn't work is because a lambda is not a std::function and so the compiler tries to create one using the fifth overload of the constructor. The problem is that both of your A constructors can be used because of this conversion and the reason that std::tuple<long long,int> and std::tuple<std::size_t,std::size_t> are constructible from each other makes this ambigious for the compiler what constructor to pick.
What you could do is explicitly cast to the desired std::function (MCVE of #PasserBy used in comments), like this:
#include <tuple>
#include <functional>
#include <iostream>
template<typename data_type, typename Type1, typename Type2>
class A
{
public:
using a_type = std::tuple<Type1, Type2>;
using b_type = std::tuple<std::size_t,std::size_t>;
A(const std::function<data_type(a_type)>&)
{
std::cout << "idx_type" << std::endl;
}
A(const std::function<data_type(b_type)>&)
{
std::cout << "point_type" << std::endl;
}
};
int main()
{
std::function<double(std::tuple<long long, int>)> func = [](auto p) -> double { return 1; };
auto c = A<double, long long, int>{
func
};
}
As #SombreroChicken mentioned, std::function<R(Args...)> has a constructor that allows any callable object c to initialize it, as long as c(Args...) is valid and returns something convertible to R.
To fix it, you may use some SFINAE machinery
#include <tuple>
#include <functional>
#include <iostream>
#include <type_traits>
template<typename data_type, typename Type1, typename Type2>
class A
{
template<typename T>
struct tag
{
operator T();
};
public:
using a_type = std::tuple<Type1, Type2>;
using b_type = std::tuple<std::size_t,std::size_t>;
template<typename C, std::enable_if_t<std::is_invocable_v<C, tag<b_type>>>* = nullptr>
A(C&& initializer)
{
std::cout << "size_t" << std::endl;
}
template<typename C, std::enable_if_t<std::is_invocable_v<C, tag<a_type>>>* = nullptr>
A(C&& initializer)
{
std::cout << "other" << std::endl;
}
};
int main()
{
auto c = A<double, long long, int>{
[](std::tuple<long long, int> p) -> double { return 1; }
};
auto c2 = A<double, long long, int>{
[](std::tuple<std::size_t, std::size_t>) -> double { return 2; }
};
}
Live
Here, we turn off the constructor if the callable can be called with b_type or a_type respectively. The extra indirection through tag is there to disable the conversion between tuples of different types
On the following code I defined an unsigned int called my_type, which I use to print the maximum value of the type itself:
#include <iostream>
#include <limits>
#include <cmath>
...
using namespace std;
int main() {
typedef unsigned int my_type;
const my_type max_int = numeric_limits<my_type>::max():
cout << max_int << endl;
return 0;
}
How can I do the same for multiple types without having to duplicate this code?
I tried creating a string array that would store types unsigned int and long (as an example), but that didn't work:
string current_type[2] = {"unsigned int", "long"};
loop{
typedef current_type[0..1] my_type;
const my_type max_int = numeric_limits<my_type>::max();
}
I have also tried using templates, but couldn't figure it out how to do it.
Is this even possible?
#include <iostream>
#include <limits>
using namespace std;
template <typename T>
void printMax()
{
cout << numeric_limits<T>::max() << endl;
}
int main()
{
printMax<unsigned int>();
printMax<double>();
return 0;
}
And:
$ g++ test.cpp && ./a.out
4294967295
1.79769e+308
C++ has no reflection so you can't convert c++ string to type name. But you can use variadic templates for your task.
#include <iostream>
#include <limits>
#include <cmath>
using namespace std;
template <typename ... Args>
struct TL;
template <typename T>
struct TL<T>
{
static void print()
{
const T max_int = numeric_limits<T>::max();
cout << max_int << endl;
}
};
template <typename T, typename ... Args>
struct TL<T, Args...>
{
static void print()
{
TL<T>::print();
TL<Args...>::print();
}
};
int main(int , char** )
{
TL<int, unsigned int, short int>::print();
return 0;
}
UPDATE
More complicated example.
You can declare variadic template for holding type lists:
template <typename ... Args>
struct TypeList;
template <typename T>
struct TypeList<T>
{
typedef T type;
};
template <typename T, typename ... Args>
struct TypeList<T, Args...>
{
typedef T type;
// typedef TypeList<Args...> rest;
};
and template to perform operation, depended of type for each element in type list:
template <typename L, template <typename T> class Op>
struct ForEach;
template <typename T, template <typename T> class Op>
struct ForEach<TypeList<T>, Op>
{
void operator()()
{
Op<T>()();
}
};
template <typename T, template <typename T> class Op, typename ... Args>
struct ForEach<TypeList<T, Args...>, Op>
{
void operator()()
{
Op<T>()();
ForEach<TypeList<Args...> , Op>()();
}
};
Now, you can declare some functions like templated structs with operator()
#include <iostream>
#include <limits>
#include <cmath>
using namespace std;
template <typename T>
struct PrintNumericTypeMaxLimit
{
void operator()()
{
const T max_int = numeric_limits<T>::max();
cout << max_int << endl;
}
};
template <typename T>
struct PrintNumericTypeMinLimit
{
void operator()()
{
const T min = numeric_limits<T>::min();
cout << min << endl;
}
};
And use it with your type list:
int main(int , char** )
{
typedef TypeList<int, unsigned int, long int, short int, unsigned short int, double> myList;
ForEach<myList, PrintNumericTypeMaxLimit>()();
ForEach<myList, PrintNumericTypeMinLimit>()();
return 0;
}
You could use boost::variant to inform the types you want, boost::mpl::foreach to loop over them
and a functor to print the numeric limits in a pre-c++11 manner or with a c++11 lambda
#include <iostream>
#include <limits>
#include <boost/variant.hpp>
#include <boost/mpl/for_each.hpp>
struct printMaxNumLimits
{
template<class Type>
void operator()(Type t) {
std::cout << std::numeric_limits<Type>::max() << std::endl;
}
};
int main()
{
using variant_types = boost::variant<int, double, unsigned int>;
// pre c++11
boost::mpl::for_each<variant_types::types>(printMaxNumLimits());
// c++11
boost::mpl::for_each<variant_types::types>([](auto t){
std::cout << std::numeric_limits<decltype(t)>::max() << std::endl;
});
}
Live example
I have the following function:
template<class T>
T Check(int index);
How can I write a function, CheckTuple, which, given a tuple type, populates a tuple with calls to Check?
For example:
CheckTuple< std::tuple<int, float, std::string> >()
would return the following tuple:
std::make_tuple( Check<int>(1), Check<float>(2), Check<std::string>(3) )
The other questions I see involve unpacking a given tuple, not building one up this way.
Implementing what you're looking for becomes pretty simple using C++14's integer_sequence. If you don't have that available, here's a C++11 implementation written by Jonathan Wakely.
template<typename Tuple, int... I>
Tuple CallCheck(std::integer_sequence<int, I...>)
{
return std::make_tuple(Check<typename std::tuple_element<I, Tuple>::type>(I)...);
}
template<typename Tuple>
Tuple CheckTuple()
{
return CallCheck<Tuple>(std::make_integer_sequence<int, std::tuple_size<Tuple>::value>());
}
// Use it as
auto tup = CheckTuple<std::tuple<int, float, std::string>>();
Live demo
Here is my working test implementation. (Perhaps someone has an idea of how to improve upon it in terms of conciseness. Can I get rid of TupleInfo somehow?)
#include <typeinfo>
#include <tuple>
#include <iostream>
template<class T>
T Check(int i) {
std::cout << "getting a " << typeid(T).name() << " at position " << i << std::endl;
return T();
}
template<typename Signature>
struct TupleInfo;
template<class T, class... Args>
struct TupleInfo< std::tuple<T, Args...> > {
using Head = T;
using Tail = std::tuple<Args...>;
};
template<int N, class Tuple>
struct TupleChecker {
static Tuple CheckTuple() {
auto t = std::make_tuple(Check<typename TupleInfo<Tuple>::Head>(N));
return std::tuple_cat(t, TupleChecker<N+1, typename TupleInfo<Tuple>::Tail >::CheckTuple());
}
};
template<int N>
struct TupleChecker<N, std::tuple<> > {
static std::tuple<> CheckTuple() {
return std::tuple<>();
}
};
template<class Tuple>
Tuple CheckTuple() {
return TupleChecker<1, Tuple>::CheckTuple();
}
int main() {
std::tuple<> t0 = CheckTuple<std::tuple<> >();
std::tuple<int> t1 = CheckTuple<std::tuple<int> >();
std::tuple<int, float, std::string> t2 = CheckTuple<std::tuple<int, float, std::string> >();
return 0;
}
Since I discovered boost::lexical_cast all conversions are a breeze. That's until trying to convert a tuples elements into a string. Like Int2String or Double2String I want a way to generate a single string from a tuple of arbitrary number of elements
Since the subject of conversion has arbitrary (yet compile time known) dimension, after some research I've looked into boost::fusion and found this solution :
#include <string>
#include <boost/lexical_cast.hpp>
#include <boost/noncopyable.hpp>
#include <boost/fusion/include/for_each.hpp>
template <class Sequence>
std::string StringFromSequence(const Sequence &seq)
{
std::string result;
boost::fusion::for_each(seq, toString(result));
return result;
}
Where toString is a functor applying the lexical cast to the objects that's been called for :
struct toString: boost::noncopyable
{
explicit toString(std::string& res) : result(res)
{
}
template <class T>
void operator()(const T& v)
{
result += boost::lexical_cast<std::string>(v);
}
private:
std::string &result;
};
When trying to use that though
std::tuple<int, char, double> tup{ 1, 'a', 2.2 };
toString(tup);
I get a compilation error
error C2893: Failed to specialize function template 'enable_if, void>::type boost::fusion::for_each(const Sequence &,const F &)'
Can someone spot and correct the error ?
Are there any (maybe boost free) alternatives ? (it would take compile time recursion and I was hopefully trying to avoid all that boilerplate code)
Since this question is tagged C++11, here's my take at it:
#include <iostream>
#include <string>
#include <tuple>
template<typename T, T...>
struct integer_sequence { };
template<std::size_t N, std::size_t... I>
struct gen_indices : gen_indices<(N - 1), (N - 1), I...> { };
template<std::size_t... I>
struct gen_indices<0, I...> : integer_sequence<std::size_t, I...> { };
template<typename H>
std::string& to_string_impl(std::string& s, H&& h)
{
using std::to_string;
s += to_string(std::forward<H>(h));
return s;
}
template<typename H, typename... T>
std::string& to_string_impl(std::string& s, H&& h, T&&... t)
{
using std::to_string;
s += to_string(std::forward<H>(h));
return to_string_impl(s, std::forward<T>(t)...);
}
template<typename... T, std::size_t... I>
std::string to_string(const std::tuple<T...>& tup, integer_sequence<std::size_t, I...>)
{
std::string result;
int ctx[] = { (to_string_impl(result, std::get<I>(tup)...), 0), 0 };
(void)ctx;
return result;
}
template<typename... T>
std::string to_string(const std::tuple<T...>& tup)
{
return to_string(tup, gen_indices<sizeof...(T)>{});
}
int main(int argc, char** argv)
{
std::tuple<int, double, float> tup(1, 2.1, 3.2);
std::cout << to_string(tup) << std::endl;
}
If you want to stick with boost::lexical_cast, replace to_string with lexical_cast.
Live output on ideone
Sorry but I'm too lazy to enter the details of where you're making the mistakes, but here's a solution using fusion and C++14 polymorphic lambdas:
#include <tuple>
#include <string>
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <boost/fusion/adapted/std_tuple.hpp> // you're missing this huh? it's needed to use fusion with std::tuple
#include <boost/fusion/algorithm/iteration/for_each.hpp>
int main() {
using namespace std;
using namespace boost::fusion;
string result;
for_each(make_tuple(1, 'a', 2.2), [&result](auto &s) {
result += boost::lexical_cast<string>(s) + ' ';
});
cout << result << endl;
}
http://coliru.stacked-crooked.com/a/f110238a317eede9