Converting dataset to any stl container - c++

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

Related

Templates inferring type T from return type

I have a template as follows:
template <class T>
vector<T> read_vector(int day)
{
vector<T> the_vector;
{...}
return the_vector;
}
I would like to be able to do something like
vector<int> ints = read_vector(3);
vector<double> doubles = read_vector(4);
Is it possible for C++ templates to infer the return type from when they're called, or should I just pass a dummy argument to the template with the type I want to the vector to have? The latter works but is messier.
#include <vector>
struct read_vector
{
int day;
explicit read_vector(int day) : day(day) {}
template <typename T, typename A>
operator std::vector<T, A>()
{
std::vector<T, A> v;
//...
return v;
}
};
int main()
{
std::vector<int> ints = read_vector(3);
std::vector<double> doubles = read_vector(4);
}
DEMO

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
}

How to convert boost::Makevariantover to vector

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);

C++ class template specialization with pointers

I have a tree structure of the following format:
template <typename DataType>
class Tree {
DataType *accessData() { return data; }
Tree *child1, *child2;
DataType *data;
};
template <typename DataType>
class Root : public Tree<DataType> {
// root provides storage of nodes; when it goes out of scope, the
// entire tree becomes invalid
MemoryPool<Tree> nodeStorage;
MemoryPool<DataType> dataStorage;
};
I use a variety of instantiations of this template in my program. It works quite well.
One instantiation, however, uses a DataType which is just an enum (so it's the same size as a pointer!) and because speed is essential (both when the tree is built, and when it is accessed), I'd much rather have this instantiation use the enum directly instead of a pointer. An example how I'd like the code to look (not strict):
Tree<BigClass> *foo = ...;
foo->accessData()->doBigClassThings();
Tree<int> *bar = ...;
int x = 4 + bar->accessInt();
Now of course I could just keep the current templates but I don't like this extra pointer access and especially the need to allocate ints in the root. Any ideas on how I can specialize the template to provide this functionality, or other approaches?
I've tried to specialize the template like this (and a bazillion other ways)
template <> Tree<int> { ... }
But I just keep getting compile errors. Any help would be greatly appreciated!
I would recommend using a traits class to deduce the type of object stored in Tree.
// The default traits.
template <typename DataType> struct TreeDataType
{
using Type = DataType*;
};
template <typename DataType>
class Tree {
// Define the data type using the traits class.
using Data = typename TreeDataType<DataType>::Type;
Data accessData() { return data; }
Tree *child1, *child2;
Data data;
};
and then specialize TreeDataType for MyEnum.
template <> struct TreeDataType<MyEnum>
{
using Type = MyEnum;
};
I suggest defining multiple data classes with the same interface that you can use as DataType template parameters. Abstract the way the data is stored from the way the data is accessed.
template<typename T>
class value_data
{
private:
T _value;
public:
T& access() { return _value; }
const T& access() const { return _value; }
};
template<typename T>
class unique_ptr_data
{
private:
std::unique_ptr<T> _value;
public:
T& access() { assert(_value != nullptr); return *_value; }
const T& access() const { assert(_value != nullptr); return *_value; }
};
enum class my_enum { /* ... */ };
class my_enum_data
{
private:
my_enum _value;
public:
my_enum& access() { return _value; }
const my_enum& access() const { return _value; }
};
Then, in your Tree class, you can use them through their common interface:
template <typename DataType>
class Tree {
auto& accessData() { return data.access(); }
Tree *child1, *child2;
DataType data;
};

Variadic template type unpacking into map keys

I'm trying to create a class which will contain a map of type_index keys mapped to pointers of each type passed as a template argument. This would allow me to specify a series of types my class will rely on in it's declaration.
I've done a bit of research but can only seem to find ways to unpack arguments, rather than types. I'm new to this subject, and would appreciate any clarification on terminology, or references to relevant text.
template <typename T>
T* SomeFakeFactoryGetter() { return new T(); }
template <class... Injected>
class UtilityProvider
{
public:
template <class U>
U* GetUtility()
{
std::type_index idx = std::type_index(typeid(U));
assert(_injectedClasses.find(idx) != _injectedClasses.end());
return reinterpret_cast<U*>(_injectedClasses[idx]);
}
// **
// How would I *unpack* all types for use as indices into my map?
// ( I realise this function is not what I want.)
template <Injected... C>
void Unpack()
{
_injectedClasses[std::type_index(typeid(C))] = SomeFakeFactoryGetter<C>();
}
private:
typedef std::unordered_map<std::type_index, void*> InjectedMap;
InjectedMap _injectedClasses;
};
class Bar{ public: void A() { printf("Hello bar"); } };
class Baz{ public: void B() { printf("Hello baz"); } };
class Nope {};
class Foo : public UtilityProvider<Bar, Baz>
{
public:
Foo()
{
GetUtility<Bar>()->A();
GetUtility<Nope>(); // Fail. User must specify which utilities this class will use.
}
};
What I've done in this situation is to create a dummy function to expand these expressions into, but it looks quite hideous:
template <int ... Dummies>
void dummy(int&& ...){}
template <class ... C>
void Unpack()
{
dummy(((_injectedClasses[std::type_index(typeid(C))] =
SomeFakeFactoryGetter<C>()), 0)...);
}
Note that in your case I think you'll be better off with using insert with an initializer_list:
template <class ... C>
void Unpack()
{
_injectedClasses.insert({std::make_pair(std::type_index(typeid(C)),
SomeFakeFactoryGetter<C>())...});
}
I couldn't find a direct mention of this but I believe there is an important difference between the two methods, in case you didn't already know. insert will not override existing key-value pairs, whereas operator[] will. This can affect which method you should use if if this is important to you.
An alternative approach:
template <typename ... C> struct Unpacker;
template <typename Tail, typename ... Queue>
struct Unpacker<Tail, Queue...>
{
void operator () (InjectedMap& injectedClasses) const
{
_injectedClasses[std::type_index(typeid(Tail))] = SomeFakeFactoryGetter<Tail>();
Unpacker<Queue...>()(injectedClasses);
}
};
template <>
struct Unpacker<>
{
void operator () (InjectedMap& injectedClasses) const {}
};