Convert 2D array to std::map? - c++

An array can be converted into a std::vector easily and efficiently:
template <typename T, int N>
vector<T> array_to_vector(T(& a)[N]) {
return vector<T>(a, a + sizeof(a) / sizeof(T));
}
Is there a similar way to convert a two dimensional array into a std::map without iterating over the members? This looks like an unusual function signature, but in my particular situation, the keys and values in these maps will be of the same type.
template <typename T, int N>
map<T, T> array_to_map(T(& a)[N][2]) {
// ...?
}
Here's the test code I put together for this question. It will compile and run as-is; the goal is to get it to compile with the block comment in main uncommented.
#include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std;
template <typename T, int N>
vector<T> array_to_vector(T(& a)[N]) {
return vector<T>(a, a + sizeof(a) / sizeof(T));
}
template <typename T, int N>
map<T, T> array_to_map(T(& a)[N][2]) {
// This doesn't work; members won't convert to pair
return map<T, T>(a, a + sizeof(a) / sizeof(T));
}
int main() {
int a[] = { 12, 23, 34 };
vector<int> v = array_to_vector(a);
cout << v[1] << endl;
/*
string b[][2] = {
{"one", "check 1"},
{"two", "check 2"}
};
map<string, string> m = array_to_map(b);
cout << m["two"] << endl;
*/
}
Again, I'm not looking for answers with code that iterates over each member of the array... I could write that myself. If it can't be done in a better way, I'll accept that as an answer.

The following works fine for me:
template <typename T, int N>
map<T, T> array_to_map(T(& a)[N][2])
{
map<T, T> result;
std::transform(
a, a+N, std::inserter(result, result.begin()),
[] (T const(&p)[2]) { return std::make_pair(p[0], p[1]); }
);
return result;
}
If you have C++03 you could use
template <typename T>
static std::pair<T, T> as_pair(T const(&p)[2]) {
return std::make_pair(p[0], p[1]);
}
template <typename T, int N>
map<T, T> array_to_map(T(& a)[N][2]) {
map<T, T> result;
std::transform(a, a+N, std::inserter(result, result.begin()), as_pair<T>);
return result;
}
Full demo http://liveworkspace.org/code/c3419ee57fc7aea84fea7932f6a95481
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <iterator>
using namespace std;
template <typename T, int N>
vector<T> array_to_vector(T const(& a)[N]) {
return vector<T>(a, a + sizeof(a) / sizeof(T));
}
template <typename T>
static std::pair<T, T> as_pair(T const(&p)[2])
{
return std::make_pair(p[0], p[1]);
}
template <typename T, int N>
map<T, T> array_to_map(T const(& a)[N][2])
{
map<T, T> result;
// C++03: std::transform(a, a+N, std::inserter(result, result.begin()), as_pair<T>);
std::transform(
a, a+N, std::inserter(result, result.begin()),
[] (T const(&p)[2]) { return std::make_pair(p[0], p[1]); }
);
return result;
}
int main() {
int a[] = { 12, 23, 34 };
vector<int> v = array_to_vector(a);
cout << v[1] << endl;
const string b[][2] = {
{"one", "check 1"},
{"two", "check 2"}
};
map<string, string> m = array_to_map(b);
cout << m["two"] << endl;
}

Related

Function that can take arrays with different dimensions

Is there a method to create a single function that can take any dimension of vector without overloading?
Currently I have,
someFunction(vector<int> a)
someFunction(vector<vector<int> > a)
someFunction(vector<vector<vector<int> > > a)
However, would it be possible to have a function:
singleFunction(<n-dimension vector>)
{
// Get dimension of array/vector
}
You can use a recursive template function
#include <iostream>
#include <vector>
void func(int el) {
std::cout << el << std::endl;
}
template<typename T>
void func(std::vector<T> v) {
for (const T& el : v) {
func(el);
}
}
int main() {
std::vector<std::vector<int>> v {{1, 2}, {2, 3}};
func(v);
return 0;
}
It's calling it itself for each element until it reaches elements of type int.
To get the dimension you can use the same pattern:
#include <iostream>
#include <vector>
template<typename T>
int someFunction(std::vector<T> v, int dim = 1);
template<>
int someFunction(std::vector<int> v, int dim) {
return dim;
}
template<typename T>
int someFunction(std::vector<T> v, int dim) {
return someFunction(T(), dim + 1);
}
template<typename T>
void singleFunction(std::vector<T> v) {
int dim(someFunction(v));
std::cout << dim << std::endl;
// Do something
}
int main() {
std::vector<std::vector<std::vector<int>>> v {{{1, 0}, {2, 4}}, {{2, 2}, {3, 0}}};
singleFunction(v);
singleFunction(std::vector<std::vector<int>>());
singleFunction(std::vector<int>());
return 0;
}
Here it creates a new object of value type and calls itself until its value type is int. Every time it increments the dimension.
Perhaps you could try this approach, I think this is exactly what you are asking (adopted from std::rank):
#include <iostream>
#include <vector>
#include <type_traits>
template<typename T>
struct vector_rank : public std::integral_constant<std::size_t, 0> {};
template<typename T>
struct vector_rank<std::vector<T>> : public std::integral_constant<std::size_t, vector_rank<T>::value + 1> {};
template<typename T>
size_t GetVectorRank(T)
{
return vector_rank<T>::value;
}
int main()
{
std::vector<std::vector<std::vector<std::vector<std::vector<int>>>>> v1;
std::cout << GetVectorRank(v1) << std::endl;
std::vector<std::vector<std::vector<int>>> v2;
std::cout << GetVectorRank(v2) << std::endl;
return 0;
}
The second template be selected recursively while the type is std::vector<T>, the first template will be selected for everything else as well as at the end of recursion. The above example will return:
5
3
Demo: https://ideone.com/CLucGA
With C++17 you can write a pretty simple solution:
template<typename T >
constexpr int func(){
if constexpr (is_vector<typename T::value_type>::value )
return 1+func<typename T::value_type>();
return 1;
}
int main() {
cout<< func<vector<vector<vector<vector<vector<int>>>>>>() <<endl;
return 0;
}
which return 5 as expected.
You need to define is_vector as follows:
template<class T>
struct is_vector{
static bool const value = false;
};
template<class T>
struct is_vector<std::vector<T> > {
static bool const value = true;
};
A simple template should solve this. From memory:
template <T> singleFunction(vector<T> &t) {
return t.size();
}
you can get the dimension with this code
#include <vector>
#include <iostream>
template<unsigned N, typename T>
struct meta {
static unsigned func() {//terminale recursion case
return N;
}
};
template<unsigned N, typename T>
struct meta<N, std::vector<T> > {//mid recursion case
static unsigned func() {
return meta<N + 1, T>::func();
}
};
template<typename T>
unsigned func(T) { //adapter to deduce the type
return meta<0, T>::func();
}
int main() {
std::cout << func(std::vector<std::vector<std::vector<int> > >()) << std::endl;
std::cout << func(std::vector<int>()) << std::endl;
std::cout << func(int()) << std::endl;
std::cout << func(std::vector<std::vector<std::vector<std::vector<std::vector<std::vector<int> > > > > >()) << std::endl;
return 0;
}
will output
3
1
0
6

Check if object is instance of class with template

My class:
template < typename T >
Array<T>{};
(Source data is stored in vector)
I have an object:
Array< string > a;
a.add("test");
And I have an object:
Array< Array< string > > b;
b.add(a);
How can I check:
Is b[0] an instance of Array (regardless of template type)?
Is a[0] an instance of any type except Array?
If you can use C++11, creating your type traits; by example
#include <string>
#include <vector>
#include <iostream>
#include <type_traits>
template <typename T>
struct Array
{
std::vector<T> v;
void add (T const t)
{ v.push_back(t); }
};
template <typename>
struct isArray : public std::false_type
{ };
template <typename T>
struct isArray<Array<T>> : public std::true_type
{ };
template <typename T>
constexpr bool isArrayFunc (T const &)
{ return isArray<T>::value; }
int main()
{
Array<std::string> a;
Array<Array<std::string>> b;
a.add("test");
b.add(a);
std::cout << isArrayFunc(a.v[0]) << std::endl; // print 0
std::cout << isArrayFunc(b.v[0]) << std::endl; // print 1
}
If you can't use C++11 or newer but only C++98, you can simply write isArray as follows
template <typename>
struct isArray
{ static const bool value = false; };
template <typename T>
struct isArray< Array<T> >
{ static const bool value = true; };
and avoid the inclusion of type_traits
--- EDIT ---
Modified (transformed in constexpr) isArrayFunc(), as suggested by Kerrek SB (thanks!).
Below is a shorter version of the solution proposed by max66 that no longer uses struct isArray.
It works in C++98 and later revisions.
#include <string>
#include <vector>
#include <iostream>
template <typename T>
struct Array
{
std::vector<T> v;
void add (T const t)
{ v.push_back(t); }
};
template <typename T>
constexpr bool isArrayFunc (T const &)
{ return false; }
template <typename T>
constexpr bool isArrayFunc (Array<T> const &)
{ return true; }
int main()
{
Array<std::string> a;
Array<Array<std::string>> b;
a.add("test");
b.add(a);
std::cout << isArrayFunc(a.v[0]) << std::endl; // print 0
std::cout << isArrayFunc(b.v[0]) << std::endl; // print 1
}
in c++ you can use
if(typeid(obj1)==typeid(ob2))//or typeid(obj1)==classname
cout <<"obj1 is instance of yourclassname"
in your case you can check that with typeid(obj1)==std::array

Passing in a function which increments elements of boost::fusion:vector

I found the following code which I am using as a basis. It describes how to populate a boost::fusion::vector with the values 6:
#include <boost/fusion/algorithm.hpp>
#include <boost/fusion/container.hpp>
struct F {
F(int blah): blah(blah){}
template <typename T>
void operator()(T& t) const {
t = blah;
}
int blah;
};
template <typename T>
void apply_for_each_to_assign(T &t)
{
boost::fusion::for_each(t, F(6));
}
int main() {
boost::fusion::vector<int, double, int> idi;
apply_for_each_to_assign(idi);
}
My question is this, instead of populating every element with the value 6- what would be the neatest way to have every element incrementing by one? So
v[0] = 1
v[1] = 2
etc? I presume I would need to write an increment function but I am not sure how I need to incorporate it in to the above code?
You can use fold.
fold takes a function A f(A, B) where B is your element type, and a intial A value and call it on all the elements. It is rougly equivalent to f(f(f(initial, first_elem), second_elem), third_elem).
You should declare the functor like this:
struct accumulator
{
typedef int result_type;
template<typename T>
int operator()(int value, T& t) const
{
t += value;
return value + 1;
}
};
And here's the usage:
template <typename T>
void apply_for_each_to_assign(T &t)
{
boost::fusion::fold(t, 1, accumulator());
}
Here a whole example with printing:
#include <boost/fusion/algorithm/iteration/fold.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/include/fold.hpp>
#include <boost/fusion/container.hpp>
#include <iostream>
struct accumulator
{
typedef int result_type;
template<typename T>
int operator()(int value, T& t) const
{
t += value;
return value + 1;
}
};
struct Print {
template <typename T>
void operator()(T& t) const {
std::cout << t << std::endl;
}
};
template <typename T>
void apply_for_each_to_assign(T &t)
{
boost::fusion::fold(t, 1, accumulator());
boost::fusion::for_each(t, Print());
}
int main()
{
boost::fusion::vector<int, double, int> idi;
apply_for_each_to_assign(idi);
}

Convert a std::vector of a boost::variant type

How might I implement the function below to convert from vector of Value to a Container? I wish to assert if not all the members of values are of the same type, i.e. if the vector contains a mix of strings and ints. This is because the function's return value is either a std::vector<int> or a std::vector<std::string>.
typedef boost::variant<int, std::string> Value;
typedef boost::variant<std::vector<int>, std::vector<std::string> > Container;
Container valuesToContainer(const std::vector<Value>& values)
{
return Container();
}
struct converter_visitor : public boost::static_visitor<Container>
{
const std::vector<Value> & _cont;
converter_visitor(const std::vector<Value> &r) : _cont(r) {}
template<class T>
Container operator()(const T &) const {
std::vector<T> ans;
ans.reserve(_cont.size());
for (int i=0;i < _cont.size();++i)
ans.push_back( boost::get<T>(_cont[i]));
return ans;
}
};
Container valuesToContainer(const std::vector<Value> & values) {
//assuming !values.empty()
return boost::apply_visitor( converter_visitor(values),values.front());
}
This will throw a bad_get if not all the elements of values are of the same type.
This could come in handy, maybe:
template <typename... T> using VariantVector = std::vector<boost::variant<T...>>;
template <typename... T> using VectorPack = std::tuple<std::vector<T>...>;
template <typename... T>
VectorPack<T...> splitVectors(VariantVector<T...> const &values);
The difference with the function requested by the OP is that instead of 'erroring' when not all element types agree, it will return a tuple of vectors ("VectorPack"), and you can simply select which is the one you want.
Demo program:
#include <boost/variant.hpp>
#include <boost/variant/static_visitor.hpp>
#include <tuple>
#include <vector>
using std::get;
template <typename... T> using VariantVector = std::vector<boost::variant<T...>>;
template <typename... T> using VectorPack = std::tuple<std::vector<T>...>;
namespace detail
{
template <typename T>
struct VectorSplitterMixin {
void operator()(T const& v) { _bucket.push_back(v); }
std::vector<T> _bucket;
};
template <typename... T>
struct VectorSplitter : boost::static_visitor<>, VectorSplitterMixin<T>...
{
typedef VectorPack<T...> product_t;
product_t product() {
return product_t { std::move(static_cast<VectorSplitterMixin<T>*>(this)->_bucket)... };
}
};
}
template <typename T> struct X;
template <typename... T>
VectorPack<T...> splitVectors(VariantVector<T...> const &values)
{
auto splitter = detail::VectorSplitter<T...>();
for (auto& val : values)
boost::apply_visitor(splitter, val);
return splitter.product();
}
int main()
{
typedef boost::variant<int, std::string> Value;
typedef boost::variant<std::vector<int>, std::vector<std::string> > Container;
const std::vector<Value> vec { 42, "hello world", 1, -99, "more" };
auto vectorPack = splitVectors<int, std::string>(vec);
for (auto i : get<0>(vectorPack))
std::cout << "int:" << i << ", ";
std::cout << "\n";
for (auto& s : get<1>(vectorPack))
std::cout << "string:" << s << ", ";
std::cout << "\n";
}
Printing:
int:42, int:1, int:-99,
string:hello world, string:more,

Template function taking a std::vector or std::array

I have a function that currently accepts 2 vectors that can contain any plain old data ...
template <class T>
void addData(const vector<T>& yData, vector<T> xData)
{ .. }
Question:
Would it be possible to modify it to take two std::array or two std::vector, or even a combination thereof, given that these containers take a different number of template arguments?
Sure, it's just a matter of creating a suitable type trait. The example just uses a function f() with one argument but it is trivial to extend to take any number of arguments.
#include <array>
#include <vector>
#include <deque>
#include <utility>
#include <cstddef>
template <typename T>
struct is_array_or_vector {
enum { value = false };
};
template <typename T, typename A>
struct is_array_or_vector<std::vector<T, A>> {
enum { value = true };
};
template <typename T, std::size_t N>
struct is_array_or_vector<std::array<T, N>> {
enum { value = true };
};
template <typename T>
typename std::enable_if<is_array_or_vector<T>::value>::type
f(T const&)
{
}
int main()
{
f(std::vector<int>()); // OK
f(std::array<int, 17>()); // OK
f(std::deque<int>()); // ERROR
}
Why not just use this, which works with any container using random-access iterators, including plain old arrays. If you can use iteration instead of indexing, you can do away with the random-access requirement as well.
template <typename Cnt1, typename Cnt2>
void addData(const Cnt1& yData, Cnt2 xData) // is pass-by-value intended?
{
using std::begin;
using std::end;
typedef decltype(*begin(yData)) T;
const auto sizeY = end(yData) - begin(yData);
const auto sizeX = end(xData) - begin(xData);
// ...
}
C++03 version (doesn't support plain old arrays):
template <typename Cnt1, typename Cnt2>
void addData(const Cnt1& yData, Cnt2 xData) // is pass-by-value intended?
{
typedef Cnt1::value_type T;
const size_t sizeY = yData.end() - yData.begin();
const size_t sizeX = xData.end() - xData.begin();
// ...
}
An alternative solution:
#include <iostream>
#include <vector>
#include <array>
using std::vector;
using std::array;
template <typename Container>
struct container_helper; // undefined
template <typename T>
struct container_helper<vector<T>>
{
explicit container_helper(vector<T>& data)
: _data(data)
{}
T* get_data()
{ return &_data[0]; }
size_t get_size()
{ return _data.size(); }
private:
vector<T>& _data;
};
template <typename T, size_t N>
struct container_helper<array<T,N>>
{
explicit container_helper(array<T,N>& data)
: _data(data)
{}
T* get_data()
{ return &_data[0]; }
size_t get_size()
{ return N; }
private:
array<T,N>& _data;
};
template <typename Container1, typename Container2>
void add_data(Container1& c1, Container2& c2)
{
container_helper<Container1> c1_helper(c1);
container_helper<Container2> c2_helper(c2);
/* do whatever you want with the containers */
std::cout << "c1 size " << c1_helper.get_size() << std::endl;
std::cout << "c2 size " << c2_helper.get_size() << std::endl;
}
int main()
{
vector<int > v_ints(3);
array<int, 2> a_ints;
add_data(v_ints, a_ints);
}