How to convert boost::Makevariantover to vector - c++

I have a boost::makevariantover. How can I convert that to a vector . Any samples will be helpful using boost::apply_visitor
class pixel_visitor
: public boost::static_visitor<>
{
public:
template <typename T>
void operator() (const ome::compat::shared_ptr<PixelBuffer<T> >& v)
{
std::cout << std::real(v);
}
};
pixelBuffer test= buf.vbuffer();
test.apply_visitor(&pixel_visitor());
where
typedef boost::make_variant_over<pixel_buffer_types>::type pixelBuffer;

Instead of .vbuffer() call .array(), it already applies the/a visitor "for you":
template<typename T>
inline typename PixelBuffer<T>::array_ref_type&
VariantPixelBuffer::array()
{
detail::VariantPixelBufferVisitor<T> v;
return boost::apply_visitor(v, buffer).array();
}
or .data() for the raw type.

We don't know what your pixelbuffer types are.
Regardless, if you know how to convert those to vectors, you could simply return that from the visitor's call operator:
class pixel_visitor
: public boost::static_visitor<std::vector<WhatEverYouWant> >
{
public:
template <typename T>
result_type operator() (const ome::compat::shared_ptr<PixelBuffer<T> >& v)
{
std::vector<WhatEverYouWant> result;
// do your conversion here
return result;
}
};
So you can e.g.
std::vector<WhatEverYouWant> applied;
applied = boost_apply_visitor(pixel_visitor(), test);

Related

overlaoding the function template whose parameters are same

It's a pity that there are some APIs provided by others that are out of my control and the said APIs return the same type(i.e. uint8_t other than the enum type).
But the meaning is different when the same value is returned by the different APIs. I hope to use overloading to convert the returned value to readable strings.
However, as per this answer, which says:
a typedef is just another name for the same type. But you can only overload on different types.
I thought and thought, and I found a solution. But I think there must be a better one. How?
But when I finish the code snippet below. I am more confused.
Since Demo::Foo::SampleType and Demo::Bar::SampleTypeare the same thing, so the overloading should not work. But the code snippet works well! What a surprise!
Here is the demo code snippet for my solution:
#include <iostream>
#include <map>
namespace Demo
{
class Foo
{
public:
using SampleType = uint8_t;
SampleType GetFooData(){return SampleType{1};}
};
class Bar
{
public:
using SampleType = uint8_t;
SampleType GetBarData(){return SampleType{2};}
};
}
//////////////////code above is provided by others/////////////
template <typename T>
void FindAndPrint(const T& val, const std::map<T, std::string>& mp)
{
auto itr = mp.find(static_cast<T>(val));
if(itr != mp.end())
{
std::cout << itr->second;
}
else
{
std::cout << "can't classify";
}
std::cout << std::endl;
}
template <typename ServiceName>
void Print(const typename ServiceName::SampleType& data);
template <>
void Print<Demo::Foo>(const typename Demo::Foo::SampleType& data)
{
enum class Color
{
Blue = 1,
Red = 2,
};
std::map<Color, std::string> mp ={
{Color::Blue, "Blue"},
{Color::Red, "Red"},
};
FindAndPrint(static_cast<Color>(data), mp);
return;
}
template <>
void Print<Demo::Bar>(const typename Demo::Foo::SampleType& data)
{
// similar code like above
// When I write this line, I start to realize my solution is wrong since `Demo::Foo::SampleType` and `Demo::Foo::SampleType`are the same thing!
// But, what a surprise! This code snippet compiles and works well. Why?
enum class Animal
{
Dog = 1,
Cat = 2,
};
std::map<Animal, std::string> mp ={
{Animal::Dog, "Dog"},
{Animal::Cat, "Cat"},
};
FindAndPrint(static_cast<Animal>(data), mp);
return;
}
int main()
{
Demo::Foo foo;
Print<Demo::Foo>(foo.GetFooData());
Demo::Bar bar;
Print<Demo::Bar>(bar.GetBarData());
}
What you have is not function overload. It is template specialization. The 3 functions you have:
template <typename ServiceName>
void Print(const typename ServiceName::SampleType& data);
template <>
void Print<Demo::Foo>(const typename Demo::Foo::SampleType& data);
template <>
void Print<Demo::Bar>(const typename Demo::Foo::SampleType& data);
It doesn't really matter how you spell out the parameter type, as long the deduced type is consistent with how you primary template was defined. Which mean you can also write them as:
template<>
void Print<Demo::Foo>(const uint8_t& data);
And the reason Print<Demo::Foo>(...) and Print<Demo::Bar>(...) are considered different functions is because you are providing different template parameters. As long Demo::Foo and Demo::Bar are not the same type, then they are considered 2 different template specialization of your base template.
You can put all the specifics about how to decode the uint8_t in a template class SampleTypeInfo that you specialize for the services. If you do that properly, the Print function can be collapsed to
template <typename ServiceName>
void Print(const typename ServiceName::SampleType& data) {
typedef SampleTypeInfo<ServiceName> Info;
FindAndPrint(Info::decode(data), Info().stringMap);
}
Here is how you can implement SampleTypeInfo:
template <typename T> struct SampleTypeInfo {};
template <typename T>
struct SampleTypeInfoBase {
typedef T SampleType;
static T decode(uint8_t x) {
return static_cast<T>(x);
}
std::map<T, std::string> stringMap;
protected:
void regString(T k, const std::string& v) {
stringMap[k] = v;
}
};
template <>
struct SampleTypeInfo<Demo::Foo> : public SampleTypeInfoBase<Color> {
SampleTypeInfo() {
regString(Color::Blue, "blue");
regString(Color::Red, "red");
}
};
template <>
struct SampleTypeInfo<Demo::Bar> : public SampleTypeInfoBase<Animal> {
SampleTypeInfo() {
regString(Animal::Cat, "cat");
regString(Animal::Dog, "dog");
}
};

How to add element to various container depending of type using template

I've got rather silly question but I hope that you can help me with that.
I've got class with multiple vectors, and this vectors have different storage types.
class BaseClass{
std::string Name;
}
class B : public BaseClass{
}
class C : public BaseClass{
}
class A{
vector<std::pair<std::string, B>> V1;
vector<std::pair<std::string, C>> V2;
}
inside my class A there is a template function to add elements to this vectors:
template <class T> void addElement(T Obj);
I want this situation to happen:
A a;
B b;
C c;
a.addElement<B>(b) -> then element b is added to vector V1
a.addElement<C>(c) -> then element c is added to vector V2
I came up with something like this:
template <class T> void addElement(T Obj){
std::pair<std::string, T> AddedPair(Obj.Name, Obj);
if (typeid(T) == typeid(B))
V1.push_back(AddedPair);
if (typeid(T) == typeid(C))
V2.push_back(AddedPair);
}
But unfortunetly this code won't compile because somehow template is compiled as a whole and if I use B as a template argument then compiler cannot convert B to C despite that program will never reach a point where this convertions can happened :(
Do you have any suggestions how can I solve this problem? I would be very greatful.
Instead of having
template <class T> void addElement(T Obj);
Just overload the function instead. That would give you
void addElement(const B& Obj)
{
V1.push_back({Obj.Name, Obj});
}
void addElement(const C& Obj)
{
V2.push_back({Obj.Name, Obj});
}
This saves you all the syntax of specializing the template or needing C++17 and if constexpr to make the decision at compile time.
The reason
template <class T> void addElement(T Obj){
std::pair<std::string, T> AddedPair(Obj.Name, Obj);
if (typeid(T) == typeid(B))
V1.push_back(AddedPair);
if (typeid(T) == typeid(C))
V2.push_back(AddedPair);
}
Doesn't work is the code in each if block needs to be valid (even if it could never be reached), but it can't be because you would be adding a different type into the vectors. if constexpr helps but I find overloading is just as much typing and makes the code non-backwards compatible.
That means you would either have to specialize the template like
template <class T> void addElement(T Obj);
template <> void addElement(B Obj)
{
V1.push_back({Obj.Name, Obj});
}
template <> void addElement(C Obj)
{
V1.push_back({Obj.Name, Obj});
}
or using if constexpr:
template <class T> void addElement(T Obj){
std::pair<std::string, T> AddedPair(Obj.Name, Obj);
if constexpr(std::is_same_v<T, B>)
V1.push_back(AddedPair);
if constexpr(std::is_same_v<T, C>)
V2.push_back(AddedPair);
}
This may be a use case for a Tagged Tuple library. It makes it possible to index containers by associated type. So code dealing with dozens of similar vector<std::pair<std::string, B>> V1; fields becomes generic:
#include <vtt/container/Tagged Tuple.hpp>
#include <string>
#include <type_traits>
#include <vector>
#include <utility>
class BaseClass{::std::string Name;};
class B : public BaseClass{};
class C : public BaseClass{};
class A
{
public: template<typename x_Item> using
t_Vector = ::std::vector<::std::pair<::std::string, x_Item>>;
public: using
t_Vectors = ::n_vtt::n_container::t_TaggedTuple
<// index type -> value type mapping
B, t_Vector<B>
, C, t_Vector<C>
>;
private: t_Vectors m_vectors;
public: template<typename x_Item> void
Add_Item(x_Item && item)
{
m_vectors
// invoke either Get_MutableItem<B> or Get_MutableItem<C>
.Get_MutableItem<::std::remove_reference_t<::std::remove_cv_t<x_Item>>>()
// add item into corresponding std::vector
.emplace_back(::std::string{}, ::std::forward<x_Item>(item));
}
};
int main()
{
A a;
a.Add_Item(B{});
C c{};
a.Add_Item(c);
return 0;
}
You might use "generic getter" for your vector:
class A
{
public:
template <typename T>
std::vector<std::pair<std::string, T>>& getVector() {
auto vectors = std::tie(V1, V2);
return std::get<std::vector<std::pair<std::string, T>>&>(vectors);
}
template <class T>
void addElement(T Obj) {
getVector<T>().emplace_back(Obj.Name, Obj);
}
std::vector<std::pair<std::string, B>> V1;
std::vector<std::pair<std::string, C>> V2;
};
Changing your member might make sense to have std::tuple directly.
and you might want to templatize the whole class:
template <typename ... Ts>
class A_Impl
{
private:
template <typename T>
decltype(auto) getVector() const {
return std::get<std::vector<std::pair<std::string, T>>>(Vs);
}
template <typename T>
decltype(auto) getVector() {
return std::get<std::vector<std::pair<std::string, T>>>(Vs);
}
public:
template <class T>
void addElement(T Obj) {
getVector<T>().emplace_back(Obj.Name, Obj);
}
private:
std::tuple<std::vector<std::pair<std::string, Ts>>...> Vs;
};
using A = A_Impl<B, C>;
If you are going to use your vectors in a few places you could specialise a template to get the correct vector once, then your main template code can be generic:
class A{
public:
template < typename T >
void addElement(T obj)
{
getVector<T>().push_back(std::make_pair(obj.Name,obj));
}
template < typename T >
T& getElement(size_t index)
{
return getVector<T>().at(index).second;
}
private:
vector<std::pair<std::string, B>> V1;
vector<std::pair<std::string, C>> V2;
template < typename T >
vector<std::pair<std::string, T>>& getVector();
};
template <>
vector<std::pair<std::string, B>>& A::getVector<B>() { return V1; }
template <>
vector<std::pair<std::string, C>>& A::getVector<C>() { return V2; }
What if you make use of the shared BaseClass like this??
You will have to create a common interface for BaseClass, I am not sure how much B and C will differ in terms of functionality though.
class BaseClass{
public:
std::string Name;
};
class B : public BaseClass{
};
class C : public BaseClass{
};
class A{
public:
std::vector<std::pair<std::string, std::unique_ptr<BaseClass>> > V1;
std::vector<std::pair<std::string, std::unique_ptr<BaseClass>> > V2;
template <class T> void addElement(T Obj)
{
std::pair<std::string, std::unique_ptr<T>> AddedPair(Obj.Name, std::make_unique<T>(Obj));
if (typeid(T) == typeid(B))
V1.push_back(AddedPair);
else if (typeid(T) == typeid(C))
V2.push_back(AddedPair);
}
};
int main()
{
A a;
B b;
C c;
a.addElement<B>(b) ;//-> then element b is added to vector V1
a.addElement<C>(c) ;//-> then element c is added to vector V2
}

Property system based on std::any: template type deduction

To implement a property system for polymorphic objects, I first declared the following structure:
enum class access_rights_t
{
NONE = 0,
READ = 1 << 0,
WRITE = 1 << 1,
READ_WRITE = READ | WRITE
};
struct property_format
{
type_index type;
string name;
access_rights_t access_rights;
};
So a property is defined with a type, a name and access rights (read-only, write-only or read-write). Then I started the property class as follows:
template<typename Base>
class property : property_format
{
public:
template<typename Derived, typename T>
using get_t = function<T(const Derived&)>;
template<typename Derived, typename T>
using set_t = function<void(Derived&, const T&)>;
private:
get_t<Base, any> get_f;
set_t<Base, any> set_f;
The property is associated to a base type, but may (and will) be filled with accessors associated to an instance of a derived type. The accessors will be encapsulated with functions accessing std::any objects on an instance of type Base. The get and set methods are declared as follows (type checking are not shown here to make the code minimal):
public:
template<typename T>
T get(const Base& b) const
{
return any_cast<T>(this->get_f(b));
}
template<typename T>
void set(Base& b, const T& value_)
{
this->set_f(b, any(value_));
}
Then the constructors (access rights are set to NONE to make the code minimal):
template<typename Derived, typename T>
property(
const string& name_,
get_t<Derived, T> get_,
set_t<Derived, T> set_ = nullptr
):
property_format{
typeid(T),
name_,
access_rights_t::NONE
},
get_f{caller<Derived, T>{get_}},
set_f{caller<Derived, T>{set_}}
{
}
template<typename Derived, typename T>
property(
const string& name_,
set_t<Derived, T> set_
):
property{
name_,
nullptr,
set_
}
{
}
The functions passed as arguments are encapsulated through the helper structure caller:
private:
template<typename Derived, typename T>
struct caller
{
get_t<Derived, T> get_f;
set_t<Derived, T> set_f;
caller(get_t<Derived, T> get_):
get_f{get_}
{
}
caller(set_t<Derived, T> set_):
set_f{set_}
{
}
any operator()(const Base& object_)
{
return any{
this->get_f(
static_cast<const Derived&>(object_)
)
};
}
void operator()(Base& object_, const any& value_)
{
this->set_f(
static_cast<Derived&>(object_),
any_cast<Value>(value_)
);
}
};
Now, considering these dummy classes.
struct foo
{
};
struct bar : foo
{
int i, j;
bar(int i_, int j_):
i{i_},
j{j_}
{
}
int get_i() const {return i;}
void set_i(const int& i_) { this->i = i_; }
};
I can write the following code:
int main()
{
// declare accessors through bar methods
property<foo>::get_t<bar, int> get_i = &bar::get_i;
property<foo>::set_t<bar, int> set_i = &bar::set_i;
// declare a read-write property
property<foo> p_i{"bar_i", get_i, set_i};
// declare a getter through a lambda
property<foo>::get_t<bar, int> get_j = [](const bar& b_){ return b_.j; };
// declare a read-only property
property<foo> p_j{"bar_j", get_j};
// dummy usage
bar b{42, 24};
foo& f = b;
cout << p_i.get<int>(f) << " " << p_j.get<int>(f) << endl;
p_i.set<int>(f, 43);
cout << p_i.get<int>(f) << endl;
}
My problem is that template type deduction doesn't allow me to declare a property directly passing the accessors as arguments, as in:
property<foo> p_i{"bar_i", &bar::get_i, &bar::set_i};
Which produces the following error:
prog.cc:62:5: note: template argument deduction/substitution failed:
prog.cc:149:50: note: mismatched types std::function<void(Type&, const Value&)> and int (bar::*)() const
property<foo> p_i{"bar_i", &bar::get_i, set_i};
Is there a way to address this problem while keeping the code "simple"?
A complete live example is available here.
std::function is a type erasure type. Type erasure types are not suitable for deduction.
template<typename Derived, typename T>
using get_t = function<T(const Derived&)>;
get_t is an alias to a type erasure type. Ditto.
Create traits classes:
template<class T>
struct gettor_traits : std::false_type {};
this will tell you if T is a valid gettor, and if so what its input and output types are. Similarly for settor_traits.
So
template<class T, class Derived>
struct gettor_traits< std::function<T(Derived const&)> >:
std::true_type
{
using return_type = T;
using argument_type = Derived;
};
template<class T, class Derived>
struct gettor_traits< T(Derived::*)() >:
std::true_type
{
using return_type = T;
using argument_type = Derived;
};
etc.
Now we got back to the property ctor:
template<class Gettor,
std::enable_if_t< gettor_traits<Gettor>{}, int> =0,
class T = typename gettor_traits<Gettor>::return_value,
class Derived = typename gettor_traits<Gettor>::argument_type
>
property(
const string& name_,
Gettor get_
):
property_format{
typeid(T),
name_,
access_rights_t::NONE
},
get_f{caller<Derived, T>{get_}},
nullptr
{
}
where we use SFINAE to ensure that our Gettor passes muster, and the traits class to extract the types we care about.
There is going to be lots of work here. But it is write-once work.
My preferred syntax in these cases would be:
std::cout << (f->*p_i)();
and
(f->*p_i)(7);
where the property acts like a member function pointer, or even
(f->*p_i) = 7;
std::cout << (f->*p_i);
where the property transparently acts like a member variable pointer.
In both cases, through overload of ->*, and in the second case via returning a pseudo-reference from ->*.
At the end of this answer is a slightly different approach. I will begin with the general problem though.
The problem is &bar::get_i is a function pointer to a member function while your alias is creating a function object which needs the class as additional template parameter.
Some examples:
Non member function:
#include <functional>
void a(int i) {};
void f(std::function<void(int)> func)
{
}
int main()
{
f(&a);
return 0;
}
This works fine. Now if I change a into a struct:
#include <functional>
struct A
{
void a(int i) {};
};
void f(std::function<void(int)> func)
{
}
int main()
{
f(std::function<void(int)>(&A::a));
return 0;
}
this gets the error:
error: no matching function for call to std::function<void(int)>::function(void (A::*)(int))'
because the std::function object also need the base class (as you do with your alias declaration)
You need a std::function<void(A,int)>
You cannot make your example much better though.
A way to make it a "bit" more easier than your example would maybe be this approach using CRTP.
#include <functional>
template <typename Class>
struct funcPtr
{
template <typename type>
using fun = std::function<void(Class,type)>;
};
struct A : public funcPtr<A>
{
void a(int i) {};
};
void f(A::fun<int> func)
{
};
int main()
{
f(A::fun<int>(&A::a));
return 0;
}
And each your "derived" classes derives from a funcPtr class which "auto generates" the specific alias declaration.

polymorphic vector without virtual or inheritance

I am trying to implement a vector that can take elements of several types, and can apply a function on all of them. This is easily done with a base class, virtual functions and inheritance, but I explicity do not want to use it. Here is how far I am so far:
#include <iostream>
#include <vector>
#include <tuple>
// this will be my new polymorphic vector;
template<typename... Ts>
class myvector {
std::tuple<std::vector<Ts>...> vectors;
template <template<typename> class funtype>
void for_each() {
}
template <template<typename> class funtype, typename X, typename... Xs>
void for_each() {
std::vector<X>& vector = std::get<std::vector<X>>(vectors);
for ( X& x : vector ) {
funtype<X> fun;
fun(x);
}
for_each<funtype, Xs...>();
}
public:
template <typename T>
void push_back(const T& t) {
std::vector<T>& vector = std::get<std::vector<T>>(vectors);
vector.push_back(t);
}
template <typename T>
void pop_back() {
std::vector<T>& vector = std::get<std::vector<T>>(vectors);
vector.pop_back();
}
/* here I would like to pass a function, or function object that
* can be expanded to all underlying types. I would prefer to just
* give a function name, that has an implementation to all types in Ts
*/
template <template<typename> class funtype>
void ForEach() {
for_each<funtype,Ts...>();
}
};
struct foo {
};
struct bar {
};
template <typename T>
void method(T& t);
template<>
void method(foo& b) {
std::cout << "foo" << std::endl;
}
template<>
void method(bar& b) {
std::cout << "bar" << std::endl;
}
int main()
{
myvector<foo,bar> mv;
mv.push_back( foo{} );
mv.push_back( bar{} );
mv.ForEach<method>();
}
at the moment I am kind of stuck, I hope you can give me some advise on how to go further.
A common solution is to use a function object with a set of operator():
struct my_fun_type
{
void operator()(foo&) const
{ std::cout << "foo\n"; }
void operator()(bar&) const
{ std::cout << "bar\n"; }
};
This allows to pass a "set" of overloaded functions to an algorithm, state, and is rather convenient to use:
my_algorithm(my_fun_type{});
If we want to add support for such function objects, we could define ForEach as follows:
template <typename Elem, typename Fun>
void for_each(Fun&& fun) {
std::vector<Elem>& vector = std::get<std::vector<Elem>>(vectors);
for ( Elem& e : vector ) {
fun(x);
}
}
template <typename Fun>
void ForEach(Fun&& fun) {
int dummy[] = { 0, (for_each<Ts>(fun), 0)... };
(void)dummy;
}
That dummy is a trick to call for_each for all types in Ts. The (void)dummy is intended to suppress a compiler warning (dummy is never read from).
You can learn more about this technique in other Q&As, such as that one.
The Fun&& is not an rvalue reference, but a universal reference.
Note that the above example differs from many Standard Library algorithms, which take the function object by value:
template <typename Elem, typename Fun>
void for_each(Fun fun) {
std::vector<Elem>& vector = std::get<std::vector<Elem>>(vectors);
std::for_each(vector.begin(), vector.end(), std::move(fun));
}
template <typename Fun>
void ForEach(Fun fun) {
int dummy[] = { 0, (for_each<Ts>(fun), 0)... };
(void)dummy;
}
To pass a set of overloaded free functions, we can wrap them in a function object (thank #Yakk for the suggestion):
struct method_t
{
template<class... Ts>
void operator()(Ts&&... ts) const
{ method( std::forward<Ts>(ts)... ); }
};
In C++1y, such a function object type can be created with less boilerplate using a polymorphic lambda:
[](auto&&... pp)
{ method( std::forward<decltype(pp)>(pp)... ); }

Converting dataset to any stl container

I have some data sets of known types that I'd like to convert into stl
containers by specifying the desired types like this:
Dataset dataset0(....);
Dataset dataset1(....);
Dataset dataset2(....);
int i = dataset0.convert<int>();
vector<int> vi = dataset1.convert<vector<int> >();
pair<vector<bool>, pair<bool, float> > complex = dataset2.convert<vector<pair<vector<bool>, pair<bool, float> >> >();
therefor I have made the following function in my Dataset class:
class Dataset
{
....
template<typename T>
T convert();
};
It's trivial to implement for the basic types like this:
template<>
int convert<int>()
{
return int(/*implementation*/);
}
But the question is, how can I do this for stl containers of any type.
Something like this:
template<>
vector<T> convert<vector<T> >() // ?? does not compile. where would T come from?
{
vector<T> ret;
for(/* Loop determined from data */)
{
ret .push_back(convert<T>())
}
return ret;
}
One would be tempted to simply say
template<typename T>
vector<T> convert<vector<T> >()
This however would mean that you are trying to define a partial specialization of a function template. This is not allowed in C++.
There's no easy work around. The only advice I can give is naming different variants of convert differently (convert_to_vector etc). If you wish to keep naming consistency, you can define a class template Convertor and specialize it for different types, using different convertor functions. For instance:
class Dataset
{
template<typename T>
T convert();
template<typename T>
vector<T> convert_to_vector() { return vector<T>(); }
template<typename T>
list<T> convert_to_list() { return list<T>(); }
};
template<>
int Dataset::convert<int>() { return 0; }
template<>
double Dataset::convert<double>() { return 0; }
template <typename T> class Convertor
{
public: T convert (Dataset& d) { return d.convert<int>(); }
};
template <typename T> class Convertor< vector<T> >
{
public: vector<T> convert (Dataset& d) { return d.convert_to_vector<T>(); }
};
template <typename T> class Convertor< list<T> >
{
public: list<T> convert (Dataset& d) { return d.convert_to_list<T>(); }
};
Then use it like Convertor<some-type>.convert(data).
Maybe this would do
template<typename T>
vector<T> convert();
if you mentionned vectoras an example and want to use other type of containers also, then you should define a `container_type convert_to_container_type()' method for each of them