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);
}
Related
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
I want to find all objects of given types and add them to vector.
For now I have code:
template<class T>
void fill1(std::vector<Character*> &vec2)
{
for (int i = 0; i < GameObject::allObjects.size(); i++)
{
if (dynamic_cast<T>(GameObject::allObjects[i]))
{
vec2.push_back(dynamic_cast<Character*>(GameObject::allObjects[i]));
}
}
}
template<class First, class ...T>
void fill2(std::vector<Character*> &vec2)
{
fill1<First>(vec2);
fill2<T...>(vec2);
}
template<class ... T>
std::vector<Character*> SpecialList<T...>::get()
{
std::vector<Character*> vec2;
fill2<T...>(vec2);
return vec2;
}
The code doesn't compile at all.
The error we are getting is:
could not deduce template argument for 'First'
I know that all the given types are inherited from class Character and I have a vector of all my objects (GameObject::allObjects).
Instead of recursion use parameter pack expansion inside list initialization of a dummy array e.g.:
#include <vector>
#include <memory>
#include <tuple>
#include <iostream>
#include <algorithm>
template <class... Ts>
struct tag { };
template <class T>
struct Predicate {
template <class U>
bool operator()(std::shared_ptr<U> sp) const {
return std::dynamic_pointer_cast<T>(sp) != nullptr;
}
};
template <class... Ts, class T>
std::vector<std::shared_ptr<T>> all(std::vector<std::shared_ptr<T>> &v, tag<Ts...>) {
std::vector<std::shared_ptr<T>> result;
int dummy[] {(std::copy_if(v.begin(), v.end(), std::back_inserter(result), Predicate<Ts>{}),0)...};
static_cast<void>(dummy);
return result;
}
struct A {
virtual ~A() = default;
};
struct B: A { };
struct C: A { };
int main() {
std::vector<std::shared_ptr<A>> v { std::make_shared<A>(),
std::make_shared<A>(),
std::make_shared<B>(),
std::make_shared<B>(),
std::make_shared<C>(),
std::make_shared<C>() };
std::cout << all(v, tag<B, C>{}).size() << std::endl;
}
[live demo]
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
The code below allows me to template a function
taking a parameter which is a vector of one of three different pointer types to Box objects:
const std::vector<std::shared_ptr<Box>>&
const std::vector<std::weak_ptr<Box>>&
const std::vector<Box*>&
Is there a way to extend this to support:
const vector<Box>&
const vector<std::reference_wrapper<Box>>
perhaps something in boost?
#include <vector>
#include <iostream>
class Box{
public:
Box (unsigned int id, unsigned int side): id(id), side(side){}
int volume(){
return side * side * side;
}
unsigned int id;
unsigned int side;
};
template <typename T>
struct is_box_containter {
enum { value = false };
};
template <>
struct is_box_containter <std::vector<std::shared_ptr<Box>>> {
enum { value = true };
};
template <>
struct is_box_containter <std::vector<std::weak_ptr<Box>>> {
enum { value = true };
};
template <>
struct is_box_containter <std::vector<Box*>> {
enum { value = true };
};
template <typename T>
typename std::enable_if<is_box_containter<T>::value>::type
measure(T const& boxes )
{
for (auto& box : boxes) {
std::cout << box->id << " has volume " << box->volume() << std::endl;
}
}
int main (){
std::vector<std::shared_ptr<Box>> some_boxes;
some_boxes.push_back(std::shared_ptr<Box>(new Box(1,4)));
some_boxes.emplace_back(new Box(2, 12));
Box * box_3 = new Box(3, 8);
Box * box_4 = new Box(4, 9);
std::vector<Box*> more_boxes;
more_boxes.emplace_back(box_3);
more_boxes.emplace_back(box_4);
measure(some_boxes);
measure(more_boxes);
return 0;
}
Why I am asking this question:
I have an application with two functions which implement near identical logic. One takes a list of SomeClass, the other takes a vector of pointers to SomeClass.
I am currently planning on refactoring the code to replace the list of SomeClass with a list of shared pointers to SomeClass. But the only reason I am doing this is to move the logic to a common implementation. I don't want to do that if there is a perfectly reasonable way to avoid it.
If I understood your question correctly, you could use a dereferencing mechanism like below:
template<typename T>
T& dereference(T &v) {
return v;
}
template<typename T>
const T& dereference(const T& v) {
return v;
}
template<typename T>
typename std::enable_if<!std::is_function<T>::value, T&>::type dereference(T* v) {
return dereference(*v);
}
template<typename T>
const T& dereference(const std::shared_ptr<T>& v) {
return dereference(*v);
}
template<typename T>
const T& dereference(const std::weak_ptr<T>& v) {
return dereference(*v);
}
template<typename T>
const T& dereference(const std::reference_wrapper<T>& v) {
return v;
}
and then call your data like:
template <typename T>
typename std::enable_if<is_box_containter<T>::value>::type
measure(T const& boxes )
{
for (auto& box : boxes) {
std::cout << dereference(box).id
<< " has volume " << dereference(box).volume() << std::endl;
}
}
LIVE DEMO
P.S You'll also have to define:
template <>
struct is_box_containter <std::vector<Box>> {
enum { value = true };
};
template <>
struct is_box_containter <std::vector<std::reference_wrapper<Box>>> {
enum { value = true };
};
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);
}