I want to build a generic (math) Vector struct, with template defined size.
Now I want to make it possible to access the values via x, y and z, but only if the Vector size is big enough.
Example Code:
template <unsigned int s, typename T>
struct Vector {
// Vector Data array
T v[s];
// Special vars
T& x = v[0];
T& y = v[1];
T& z = v[2];
Vector(): v{0} {}
// some vector functions
};
Now consider the following:
Vector<2, float> vf2;
// should be possible
vf2.x;
// should be impossible
vf2.z;
Vector<3, float> vf3;
// should both be possible
vf3.x;
vf3.z;
The vf2.z part should throw an error at compile time and, because of the functions, I do not want to duplicate the Vector struct.
Does anyone know how to achieve this?
Thanks in advance.
EDIT: I find a much easier way to solve your problem so here goes...
First of all I need to see something about your class design, it is not a good design, if you want everything to be public use a struct not a class, secondly, if you want to check something you need to write a method for it, so something like:
template <unsigned int s, typename T>
class Vector {
public:
T v[s];
T& x = v[0];
T& y = v[1];
T& z = v[2];
int getSize(){
return s;
};
};
Then in your driver you do something like:
Vector<2, float> vf2;
if(vf2.getSize() > 2){
vf2.x;
vf2.z;
}
else{
vf2.z
cout << "x cannot be called because size is too small.";
}
//do the same for the rest....
Related
I have the following situation. Let say we want to implement a sorted array data structure which keeps the array sorted upon insertion. At first attempt, I would do something like:
template<typename T, typename Comparator, Comparator comparator>
SortedArray {
public:
void find(T value);
void insert(T value);
void remove(T value);
}
The argument T is of course for the type of the elements in the array. Then I need a comparator to tell how to compare objects of type T so that I can keep the elements sorted. Since I want to allow for both function pointers (as in classical qsort) as well as function objects and maybe lambda as well, I need to add the template parameter for the comparator.
Now the problem is that I want the compiler to automatically deduce the 2nd Comparator argument based on the 3rd argument. Right now, a typical usage will be exploiting decltype like
int compare_int(int x, int y) {
return x - y;
}
SortedArray<int, decltype(compare_int), compare_int> myArray;
but this doesn't work with lambda and certainly I would love to just write
SortedArray<int, compare_int> myArray;
instead.
Any idea or is it actually possible in C++ at the moment?
You can non type template parameters as follows:
template<typename T, auto C >
class SortedArray
{
private:
std::vector<T> v;
public:
void sort(){ std::sort( v.begin(), v.end(), C );}
void print() { for( auto& el: v ) std::cout << el << std::endl; }
void push(T t){ v.push_back(t);}
};
bool compare_int( int a, int b )
{
return a<b;
}
int main()
{
SortedArray<int, compare_int> sa1;
sa1.push(5);
sa1.push(3);
sa1.push(7);
sa1.sort();
sa1.print();
SortedArray<int, [](int a, int b){ return a<b;} > sa2;
sa2.push(5);
sa2.push(3);
sa2.push(7);
sa2.sort();
sa2.print();
}
As you can see, you can also use a lambda as template parameter.
There is no need to do any template gymnastic with derived template parameters anymore.
I have two classes that utilize initialize lists. One is a Vector styled class that hold a list of values.
Vec.h:
template< typename T, int nDimensions = 2 >
class Vec{
private:
std::array< T, nDimensions > elements_;
public:
template <typename... U>
Vec(U... ts) : elements_{ ts... } {}
}
Then when used:
typedef Vec< int, 2 > Vec2i;
Vec2i twoi = { 1,2 };
Vec2i twoi2 = twoi; //I have copy constructor and other methods finished.
This class works all fine and dandy, however when I try to use this class with my Matrix styled class, I cant figure out the correct syntax for its constructor.
template< typename T, int X,int Y>
class Mat {
private:
std::array< Vec<T, X>, Y > elements_;
}
Id like to use it like so:
typedef Mat<int, 3,3> Mat3i;
Mat3i threemat = { {1,2,3},
{4,5,6},
{7,8,9}};
Now, iv tried using initializer lists as the constructor with some success, but I cant figure out the syntax to pass the sub lists along.
Mat(std::initializer_list<Vec<T, X>> values) {
for (auto& t : values) {
//What goes here?
}
}
Iv also tried iteration over the list and assigning them manually, but thats a no go.
Its also worth noting that its important that these classes have consecutive chunks of memory for there lists, and no other variables. Otherwise id be using other types instead of std::array. (For casting and union purposes.)
I'm debating if I need to reinterpret cast each value as a Vec then copy over the values.
As alternative:
Mat(std::initializer_list<Vec<T, X>> values) {
std::copy(values.begin(), values.end(), elements_.begin());
}
I'm an idiot.
Mat(std::initializer_list<Vec<T, X>> values) {
int i = 0;
for (auto& t : values) {
elements_[i++] = t;
}
}
I am trying to implement a type erased data structure for writing and
reading large arrays of any type in a list, with the following
requirements:
Fast insert of bulk data (receive a std::vector<T>, where T is a primitive type).
Fast read of all/latest values if types match
Read/convert if types mismatch. In most cases from primitive to primitive (e.g double->float, int->double)
The interface I was thinking of would look something like this:
class Trace {
template<typename T> std::vector<T> read();
template<typename T> std::vector<T> latest();
template<typename T> void append(std::vector<T> values);
template<typename T> void replace(std::vector<T> values);
void clear();
};
Which is then used in a TraceHandler class (Singleton structure), which allows access to traces per key:
class TraceHandler {
public:
template<typename T>
std::vector<T> read(std::string const& key);
template<typename T>
void write(std::string const& key, std::vector<T> const& val);
private:
// STore all Traces for different types
};
And a useage would look something like this:
TraceHandler th;
std::vector<double> vals(1000,1.0), res;
th.write("values",vals);
std::vector<int> resInt;
res = th.read<double>("values");
resInt = th.read<int>("values");
Our current implementation creates a Trace for each datatype and the
user has to keep track of the correct type, which is not very
flexible (e.g write using writeDouble(), read using readDouble).
My first approach was to change the type of the internal storage
vector to an any type (we are using Poco libraries, so I was using
Poco::Any and Poco::DynamicAny), but this leads to a big
performance hit.
Data is written from Devices with high frequencies (data is acquired
with up to 20khz, then written in blocks of around 4k to the Trace),
and the measured performance difference between a plain vector and one
of an Any type was of factor 500-1000 (measured 800ms vs. 4ms for big
bulk insert/read in a loop). Most of the time gets lost due to
constructor calls vs simple memcopy.
So my question is: Is there a way to implement this interface (or an
alternative) with good bulk insert/read performance?
Edit:
This is the current implementation I'm using:
class LWDynamicVector
{
private:
typedef std::vector<Poco::DynamicAny> DataList;
DataList m_data;
public:
LWDynamicVector() {}
template<typename T> std::vector<T> read() {
return std::vector<T>(m_data.begin(),m_data.end());
}
template<typename T> void writeAppend(std::vector<T> v) {
m_data.insert(m_data.end(),v.begin(),v.end());
}
template<typename T> void writeReplace(std::vector<T> v) {
m_data.assign(v.begin(),v.end());
}
};
And the Test I am using:
TEST(DynamicVector,Performance) {
typedef double Type;
size_t runs = 100; size_t N = 20480;
std::vector<Type> input;
input.reserve(N);
for(size_t i = 0; i < N; ++i) {
input.push_back(rand());
}
{
OldVector<Type> instance;
Poco::Timestamp ts;
for(size_t i = 0; i < runs; ++i) {
instance.writeAppend(input);
}
std::cout << "Old vector: time elapsed(ms) = " << ts.elapsed() / 1000.0 << std::endl;
std::vector<Type> output = instance.read();
EXPECT_EQ(output.back(),output.back());
}
{
LWDynamicVector dbv;
Poco::Timestamp ts;
for(size_t i = 0; i < runs; ++i) {
dbv.writeAppend(input);
}
std::cout << "New vector: time elapsed(ms) = " << ts.elapsed() / 1000.0 << std::endl;
std::vector<Type> output = dbv.read<Type>();
EXPECT_EQ(output.back(),output.back());
}
}
Which results in:
Old vector: time elapsed(ms) = 44.004
New vector: time elapsed(ms) = 4380.44
Regarding compiler options and optimizations: Unfortunately I'm stuck at the current settings without the option to change them. In most scenarios the build runs in debug mode, but still has to meet the timing requirements. But anyways, the performance does not improve in release mode:
Old vector: time elapsed(ms) = 20.002
New vector: time elapsed(ms) = 1013.1
I presume that the problem is in the gather data phase and not in the evaluation.
First point is that your OldVector didn't need to make any type conversions, therefore on POD data it would essentially use a memcpy on the data when it inserted.
DynamicAny is a very nice class if you really really need dynamic variable content, but deep within the class we can see (one of) the problem for performance
VarHolder* _pHolder;
which means some memory allocation for each data inserted and some house keeping.
Now an concept implementation as I can't test it, your Trace class
template<class T>
class Trace {
std::vector<T> trace;
public:
template<typename T, class U> std::vector<U> read();
template<typename T, class U> std::vector<T> latest();
template<typename T> void append(std::vector<T> values);
template<typename T> void replace(std::vector<T> values);
void clear();
};
That would work fine if you only used one T. Hide the types in TraceHandler
class TraceHandler {
public:
template<typename T, class U>
std::vector<U> read(std::string const& key);
template<typename T>
void write(std::string const& key, std::vector<T> const& val);
private:
// Store all Traces for different types
std::unordered_map<const std::string, Poco::DynamicAny> values; // abstraction
};
This only works if each key only used one T and DynamicAny can take a vector.
template<class T>
void TraceHandler::write(std::string const& key, std::vector<T> const& val) {
if (values.find(key) == values.end()) { // doesn't exists
Trace<T> temp;
temp.append(val);
values[key] = temp;
} else
values[key].append(val); // only works if DynamicAny can return original type
}
Will it work with your use case?
TraceHandler th;
std::vector<double> vals(1000,1.0), res;
th.write("values",vals);
std::vector<int> resInt;
//res = th.read("values"); // could work if DynamicAny could return original.
td.read("values", res);
//resInt = th.read("values"); // wont work as read can't guess the type
th.read("values", resInt); // read can guess the return type
// handle conversion from stored type to wanted return type
template<class T, class U>
void TraceHandler::read(std::string const& key, std::vector<U>& res) {
// convert from T to U, maybe use Poco???
... work here!!! can be slow as its after it is captured
}
// specialization where T==U ... more work needed.
template<class T, class U>
std::vector<T>& TraceHandler::read(std::string const& key, std::vector<T>& res) {
// no conversion needed
// convince DynamicAny to return the original data
res = values[key]; // will not work out of the box???
}
This should have better performance as there is only one use of Poco::DynamicAny per table per call. Some further optimizations could be made to lessen copying but that can be done later after it runs at all.
You know you are writing only primitive types. You know all these types in advance. Use a plain old union + type tag. Can't beat that. boost::variant should also work.
typedef enum { type_int, type_double } type_tag_t;
struct data_t {
type_tag_t tag;
union {
int int_elem;
double double_elem;
}
};
boost::variant should also work.
Alternatively, store entire std::vectorfuls of data in a
std::map<std::string,
boost::variant<std::vector<int>,
std::vector<double>,
...
>
> mymap;
std::vector<boost::any>
it's a library dedicated to a type that implements type erasure techniques .
boost::any
I have a std::array and a boost::fusion::vector<X, Y> which I want to pass in to func1(). This function will add a boost::fusion::vector<X, Y> instance to each std::array element.
I have to use fusion::fold() so that I can add the correct number of elements to the fusion::vector<X,Y>, right?
So I currently have something like this:
void func1(){
boost::fusion::vector<X,Y> my_vec;
std::array<boost::fusion::vector<X,Y> > my_array[10];
func2(my_vec, my_array);
}
void func2(boost::fusion::vector<X,Y> my_vec, std::array<boost::fusion::vector<X,Y> > my_array){
//THIS IS THE PART I AM UNSURE ABOUT
for(int k=0; k<10; k++){
//The first two parameters aren't so important- just included to show the idea
my_array[k] = boost::fusion::fold(my_vec, 1, some_struct);
}
}
//This part is irrelevant
struct some_struct
{
typedef int result_type;
template<typename T>
int operator()(int x, T& t) const
{
t = something(x);
//Not sure if this part needs to return a boost::fusion::vector<X, Y>
return x;
}
};
The part I am unsure about is how to use the signature of my_vec in order to create multiple boost::fusion::vector<X,Y> instances and return them back so that I can add to the array in func2().
Could somebody please advise?
EDIT - Just spotted I got the first parameter for fold() wrong, have amended my question.
I'm not sure I understood your question really well so first let's explain what fold is to try to clarify.
In general (not just for fusion) "folding" a function taking two parameters is applying it to each and every element of the vector and to the result of the application of the function to the previous element of the vector. The first element is being given the initial value.
So if I define the function to fold as A f(A, B), the folding of this function will be equivalent to (for 4 elements):
f(f(f(f(A_initial_value, B_0), B_1), B_2), B_3);
(capitalized prefix is there just to enforce type)
Now, more precisely fusion fold. It will fold the function on all the elements inside the boost::fusion::vector<>. As a boost::fusion::vector<X, Y> is equivalent to a std::tuple<X,Y> it will call f on different types:
A_final_value = f(A_initial_value, X_value), Y_value);
So, when you do:
my_array[k] = boost::fusion::fold(my_vec, 1, some_struct);
my_array[k] will receive an numeric value, and that won't compile since you've defined it as fusion::vector<X,Y>
So having trying to clarify fold, I would say no to your question, but I admit that I do not understand what you mean by "add the correct number of elements to the fusion::vector<X,Y>".
EDIT: Updating according what've been said in comment.
The goal isto generate a fibonacci sequence in your std::array<fusion::vector<int, int, int, int>> such as walking each vector of the array will give the fibonacci in the right order.
Using fusion you have to pass a state while iterating through the elements of the vector and so foldwas a good choice.
Here is my suggestion for this (but starting the fibonacci sequence at the second element and not the first, cause I didn't bother to handle the special case... sorry :) ):
template <typename Value>
struct Generator
{
// Easier to read and mandatory for fold
typedef typename std::tuple<Value, Value> result_type;
// The function that generate the fibonacci and update the Value
result_type operator()(result_type previous, Value& elem) const
{
elem = std::get<0>(previous) + std::get<1>(previous);
return std::make_tuple(std::get<1>(previous), elem);
}
};
// Use template to be a bit more generic on array size and vector type
template <typename Vector, size_t array_size, typename Value>
void func2(std::array<Vector, array_size>& array, std::tuple<Value, Value> init)
{
// The state that will be fed across the fold function
auto previous = init;
for (auto& vect: array)
{
// Generate the fibonnaci value for every element of the vector starting
// from where the state is. The return value of fold is the new state
previous = boost::fusion::fold(vect, previous, Generator<Value>());
}
}
// Tool to print the vector
struct Printer
{
template <typename Elem>
void operator()(const Elem& elem) const
{
std::cout << elem << std::endl;
}
};
// Use template to be a bit more generic on array size and vector type
template <typename Vector, size_t array_size, typename Value>
void func1(std::tuple<Value, Value> init)
{
// Create the vector
std::array<Vector, array_size> array;
// FIll it with fibonacci
func2(array, init);
// Print it
for (auto vect: array)
{
boost::fusion::for_each(vect, Printer());
}
}
http://rextester.com/XCXYX58360
I have a POD with about 30 members of various types and I will be wanting to store thousands of the PODs in a container, and then sort that container by one of those members.
For example:
struct Person{
int idNumber;
....many other members
}
Thousands of Person objects which I want to sort by idNumber or by any other member I choose to sort by.
I've been researching this for a while today and it seems the most efficient, or at least, simplest, solution to this is not use struct at all, and rather use tuple for which I can pass an index number to a custom comparison functor for use in std::sort. (An example on this page shows one way to implement this type of sort easily, but does so on a single member of a struct which would make templating this not so easy since you must refer to the member by name, rather than by index which the tuple provides.)
My two-part question on this approach is 1) Is it acceptable for a tuple to be fairly large, with dozens of members? and 2) Is there an equally elegant solution for continuing to use struct instead of tuple for this?
You can make a comparator that stores a pointer to member internaly so it knows which member to take for comparison:
struct POD {
int i;
char c;
float f;
long l;
double d;
short s;
};
template<typename C, typename T>
struct Comp {
explicit Comp(T C::* p) : ptr(p) {}
bool operator()(const POD& p1, const POD& p2) const
{
return p1.*ptr < p2.*ptr;
}
private:
T C::* ptr;
};
// helper function to make a comparator easily
template<typename C, typename T>
Comp<C,T> make_comp( T C::* p)
{
return Comp<C,T>(p);
}
int main()
{
std::vector<POD> v;
std::sort(v.begin(), v.end(), make_comp(&POD::i));
std::sort(v.begin(), v.end(), make_comp(&POD::d));
// etc...
}
To further generalize this, make make_comp take a custom comparator, so you can have greater-than and other comparisons.
1) Is it acceptable for a tuple to be fairly large, with dozens of members?
Yes it is acceptable. However it won't be easy to maintain since all you'll have to work with is an index within the tuple, which is very akin to a magic number. The best you could get is reintroduce a name-to-index mapping using an enum which is hardly maintainable either.
2) Is there an equally elegant solution for continuing to use struct instead of tuple for this?
You can easily write a template function to access a specific struct member (to be fair, I didn't put much effort into it, it's more a proof of concept than anything else so that you get an idea how it can be done):
template<typename T, typename R, R T::* M>
R get_member(T& o) {
return o.*M;
}
struct Foo {
int i;
bool j;
float k;
};
int main() {
Foo f = { 3, true, 3.14 };
std::cout << get_member<Foo, float, &Foo::k>(f) << std::endl;
return 0;
}
From there, it's just as easy to write a generic comparator which you can use at your leisure (I'll leave it to you as an exercise). This way you can still refer to your members by name, yet you don't need to write a separate comparator for each member.
You could use a template to extract the sort key:
struct A
{
std::string name;
int a, b;
};
template<class Struct, typename T, T Struct::*Member>
struct compare_member
{
bool operator()(const Struct& lh, const Struct& rh)
{
return lh.*Member < rh.*Member;
}
};
int main()
{
std::vector<A> values;
std::sort(begin(values), end(values), compare_member<A, int, &A::a>());
}
Maybe you want to have a look at boost::multi_index_container which is a very powerful container if you want to index (sort) object by different keys.
Create a class which can use a pointer to a Person member data to use for comparison:
std::sort(container.begin(), container.end(), Compare(&Person::idNumber));
Where Compare is:
template<typename PointerToMemberData>
struct Compare {
Compare(PointerToMemberData pointerToMemberData) :
pointerToMemberData(pointerToMemberData) {
}
template<typename Type
bool operator()(Type lhs, Type rhs) {
return lhs.*pointerToMemberData < rhs.*pointerToMemberData
}
PointerToMemberData pointerToMemberData;
};