In order to deal with vectors and fixed/dynamic allocation in some linear algebra problems, I built the following classes (which I would prefer not to modify ):
// Traits : n is the size of the vector, if -1 : dynamic allocation
template<typename RealType, int n = -1>
struct ClassAVectorTraits
{
typedef typename LinearAlgebraLibrary::FixedSizeVector<RealType, n> type;
};
template<typename RealType>
struct ClassAVectorTraits<T, -1>
{
typedef typename LinearAlgebraLibrary::DynamicSizeVector<RealType> type;
};
template<typename RealType>
struct ClassAVectorTraits<T, 1>
{
typedef typename RealType type;
};
// Implementation
template<typename RealType, int n = -1>
struct ClassA
{
typedef typename ClassAVectorTraits<RealType, n>::type vector;
void doSomething( const vector& vec )
{
...
}
};
Moreover I have an interface class (which I can modify) :
template<typename RealType, int n = -1>
struct UserClass
{
typedef typename ClassAVectorTraits<RealType, n>::type vector;
ClassA ca;
void doSomething( const vector& vec )
{
ca.doSomething( vec );
}
};
Now I want the user to be able to give STL vectors in input instead of LinearAlgebraLibrary vectors, so I did the following :
// A class to do automatic conversion
template<typename RealType, int n = -1>
struct Field : public ClassAVectorTraits<RealType,n>::type
{
// Constructor NOT explicit
Field( const std::vector<RealType>& vec )
{
// Copy vec into this (a LinearAlgebraLibrary vector)
}
}
template<typename RealType>
struct Field<RealType, 1> { }; // Can't derive from integral type : RealType !
// And to classes to tag the solution
template<typename RealType, int n>
struct USE_LINEAR_ALGEBRA_LIBRARY
{
typedef typename ClassAVectorTraits<RealType,n>::type vector;
};
template<typename RealType, int n>
struct USE_STL
{
typedef typename Field<RealType,n> vector;
};
And finally :
template<typename RealType, int n = -1, class VectorTag = USE_LINEAR_ALGEBRA_LIBRARY<RealType, n> >
struct UserClass
{
typedef typename VectorTag::vector vector;
ClassA ca;
void doSomething( const vector& vec )
{
ca.doSomething( vec );
}
};
And therefore, if we use the USE_STL tag, there is an automatic conversion :
UserClass<double, 2, USE_STL<double, 2> > userClass;
std::vector<double> vecSTL(2, 12.0);
userClass.doSomething( vecSTL ); // vecSTL is converted to LinearAlgebraLibrary::FixedSizeVector<double, 2>
My question : how can I deal with the n=1 case in which the vector type is an integral type. How can I define an implicit conversion between STL vector of double (size == 1) with a double ?
Any suggestions ? Thanks.
You don't have to follow the scheme of generic template when you are about to specialize. Hope this helps:
template<typename RealType>
struct Field<RealType, 1> {
typename ClassAVectorTraits<RealType,1>::type value;
operator ClassAVectorTraits<RealType,1>::type () const { return value; }
Field(const std::vector<RealType>& vec)
{
if (vec.size() == 1) value = vec[0];
else throw runtime_error("wrong size");
}
};
Related
I have a class like this:
struct X
{
enum Type { INT, FLOAT };
using val_t = std::tuple<int, float>;
X(Type t) : type(t) {}
Type type;
template<typename T>
X& operator =(T x)
{
// ???
static_assert(T is the same as `type');
// ???
std::get<type>(val) = x;
return *this;
}
val_t val;
};
Is it possible to assert at compile time if user tries to assign incompatible value?
For example:
X x1(X::INT);
x1 = 5; // OK
x1 = 3.14; // compilation error
Note: I prefer keeping the class as not a template because I need to keep its instances in collections (like std::vector etc).
You cannot: the value of type_ is run time data, compilation errors are not determined at runtime.
You could do:
enum Type { INT, FLOAT };
template<Type type_>
struct X {
using val_t = std::tuple<int, float>;
template<typename T>
X& operator =(T x) {
// ???
static_assert((type_==INT&&std::is_same<T,int>{})||(type_==FLOAT&&std::is_same<T,float>{}),
"types do not match"
);
std::get<T>(val) = x;
return *this;
}
val_t val;
};
X<INT> x1;
x1 = 5; // OK
x1 = 3.14; // compilation error
but I do not see much point.
One way would be to have a base type that does not do the checking just stores state, and a derived that knows its type.
struct Base{
enum {INT,FLOAT} Type;
// etc
};
template<Base::Type type>
struct Derived:private Base{
Derived():Base(type){}
using Base::some_method; // expose base methods
Base& get_base()&{return *this;}
Base get_base()&&{return std::move(*this);}
Base const& get_base()const&{return *this;}
template<class T>
Derived& operator=( T o){
static_assert((type_==INT&&std::is_same<T,int>{})||(type_==FLOAT&&std::is_same<T,float>{}),
"types do not match"
);
Base::operator=(std::move(o));
return *this;
}
};
Base does not check, at best it runtime asserts. Derived checks at compile time.
Niw when you know the type statically at compile time you use Derived<INT> d;; when you do not, or need to forget, use .get_base() or a Base b(type_enum_val);.
Considering that you have Type type; you can't assert at compiletime if type is INT or FLOAT or whatever you have. For that check you can only assert at runtime.
For everything else you can do a compiletime check, and a runtime check for using some template meta-programming:
namespace detail_tuple
{
template <typename T, std::size_t N, typename... ARGS>
struct get_by_type_impl {
enum {
kIdx = N
};
};
template <typename T, std::size_t N, typename... ARGS>
struct get_by_type_impl<T, N, T, ARGS...> {
enum {
kIdx = N
};
};
template <typename T, std::size_t N, typename U, typename... ARGS>
struct get_by_type_impl<T, N, U, ARGS...> {
enum {
kIdx = get_by_type_impl<T, N + 1, ARGS...>::kIdx
};
};
}
template <typename, typename>
struct validator;
template <typename T, typename... ARGS>
struct validator < T, std::tuple<ARGS...> >
{
static void validate(const std::size_t type_idx)
{
//compiletime checks
//get index of type T in ARGS...
constexpr auto ind = detail_tuple::get_by_type_impl<T, 0, ARGS...>::kIdx;
//check if index is valid
static_assert(ind < sizeof...(ARGS), "Type index out of bounds, type T is was not found in the tuple!");
//runtime checks
if (type_idx != ind)
std::cout << "Incompatible type index!\n";
}
};
struct X
{
enum Type
{
INT = 0,
FLOAT,
TYPE_COUNT,
};
using val_t = std::tuple<int, float>;
X(Type t) : type(t) {}
Type type;
template<typename T>
X& operator =(const T& x)
{
validator<T, val_t>::validate(type);
std::get<T>(val) = x;
return *this;
}
val_t val;
};
for that std::get uses type T instead of type
I am following this question in order to select the right container, but I am encountering problems.
I have a selector class that must push back into a vector of pointers, but the right one depends on its dimension (1 for vectors, 2 for matrices):
class selector
{
struct formValues : std::vector<coolvector<double>*>, std::vector<coolmatrix<double>*> { };
formValues maps;
public:
selector() { };
template<unsigned int formdim, typename F>
void operator+=(const form<formdim, F> &f)
{
typedef typename form<formdim, F>::storage_type storage_type;
typedef typename std::vector<storage_type*> pointer_type;
// Push to the right vector
formValues<pointer_type> &m = maps;
m.push_back(f.storage.get());
}
};
The forms class have a dimension and a storage, again depending on the dimension, using shared pointers:
template <bool, class if_true, class if_false>
struct type_switch
{
typedef if_false type;
};
template <class if_true, class if_false>
struct type_switch<true, if_true, if_false>
{
typedef if_true type;
};
template <class T> class coolvector {};
template <class T> class coolmatrix {};
template<unsigned int formdim, typename F>
class form
{
public:
form() = delete;
form(const std::string &s) : type(s)
{
storage = std::make_shared<storage_type>();
}
std::string type;
typedef typename type_switch<formdim == 1, coolvector<double>, coolmatrix<double>>::type storage_type;
std::shared_ptr<storage_type> storage;
};
class oneform : public form<1, oneform>
{
public:
oneform() = delete;
oneform(const std::string &s) : form(s) { };
double operator()(unsigned int i) { return i * 2; };
};
class twoform : public form<2, twoform>
{
public:
twoform() = delete;
twoform(const std::string &s) : form(s) { };
double operator()(unsigned int i, unsigned int j) { return i * 2 + j * 20; };
};
The problem is that in the selector::operator+= I get this error:
main.cpp:77:19: error: expected unqualified-id
formValues<pointer_type> &m = maps;
^
Any hints are appreciated!
formValues is not a template, so you can't write formValues<pointer_type>.
You appear to mean
pointer_type& m = maps;
to get the appropriate base class subobject of maps.
I'm in the process of creating a vector class and am trying to figure out ways to reuse the maximum amount of code for different size vectors.
Here's a basic example:
template<typename T, unsigned int D>
class Vector
{
public:
union {
T v[D];
struct {
/* T x;
* T y;
* T z;
* T w;
*/
};
};
Vector()
{
for(unsigned int i=0; i<D; ++i)
(*this)[i] = T(0);
}
Vector(T scalar)
{
for(unsigned int i=0; i<D; ++i)
(*this)[i] = scalar;
}
inline T operator[](int i) { return (*this).v[i]; }
};
I want the member variables to be publicly accessible. Ex:
Vector<float,2> vec;
printf("X: %.2f, Y: %.2f\n", vec.x, vec.y);
What I'd like to do is something along the lines of this:
template<typename T>
class Vector2 : public Vector<T,2, struct { T x; T y; }> {};
template<typename T>
class Vector3 : public Vector<T,2, struct { T x; T y; T z; }> {};
and have it override a struct in the union:
template<typename T, unsigned int D, struct C>
class Vector
{
public:
union {
T v[D];
// Place the passed struct here
};
};
Is there any feasible way to do this? I do not want to use anything other than the standard library if possible. Thanks in advance.
EDIT: After reading upon all of the answers, I have understood that the way I am using unions is incorrect! Thank you to #M.M for pointing this out. I have since chosen to go a different route, but I have selected the answer that best fit what I was looking for at the time. Once again, thank you for all of the welcomed responses below!
What you are trying to do is not allowed.
Anyway, you can do this:
template<typename T>
struct S { T x; T y; };
template<typename T>
class Vector2 : public Vector<T,2,S<T>> {};
Or this:
template<typename T>
class Vector2 : public Vector<T,2,S> {};
In the second case, Vector can be defined as:
template<typename T, unsigned int D, template<typename> class S>
class Vector {
using MyStruct = S<T>;
// ...
union {
T v[D];
MyStruct myStruct;
};
};
It doesn't scale very well to a large D, but if you're just after the four to six variants I'm imagining, you could partial-specialize a base class:
#include <iostream>
template<typename T, size_t D>
struct VectorBase;
template<typename T>
struct VectorBase<T, 2>
{
constexpr VectorBase() : v{} {}
union {
T v[2];
struct { T x, y; };
};
};
template<typename T>
struct VectorBase<T, 3>
{
constexpr VectorBase() : v{} {}
union {
T v[3];
struct { T x, y, z; };
};
};
template<typename T>
struct VectorBase<T, 4>
{
constexpr VectorBase() : v{} {}
union {
T v[4];
struct { T x, y, z, w; };
};
};
template<typename T, size_t D>
struct Vector : public VectorBase<T, D>
{
using VectorBase<T, D>::v;
using size_type = decltype(D);
using value_type = T;
constexpr Vector() : VectorBase<T,D>{} {}
constexpr Vector(T scalar) {
std::fill(std::begin(v), std::end(v), scalar);
}
constexpr T& operator[](size_type i) const noexcept { return v[i]; }
constexpr const T& operator[](size_type i) noexcept { return v[i]; }
constexpr size_type size() const noexcept { return D; }
constexpr T* data() noexcept { return &v[0]; }
constexpr const T* data() const noexcept { return &v[0]; }
};
template<typename T>
using Vector2 = Vector<T, 2>;
template<typename T>
using Vector3 = Vector<T, 3>;
template<typename T>
using Vector4 = Vector<T, 4>;
int main() {
Vector3<int> v{1};
std::cout << v[0] << ", " << v.z << "\n";
return 0;
}
Live demo: http://ideone.com/T3QHoq
If I understood you correctly your main purpose was to to declare order of fields that corresponds to the array elements of templated class. You cannot do this directly as templates does not accept inline type as parameter. To workaround the problem you could play with non-type template parameters to bind some labels to given index of an array:
#include <cstdio>
#include <unordered_map>
#include <utility>
struct Label { } x, y, z, w;
template <Label&... labels>
struct Pack { };
template <class, class>
struct VectorParent;
template <Label&... labels, size_t... Is>
struct VectorParent<Pack<labels...>, std::index_sequence<Is...>> {
static std::unordered_map<Label *, size_t> label_map;
};
template <Label&... labels, size_t... Is>
std::unordered_map<Label *, size_t> VectorParent<Pack<labels...>, std::index_sequence<Is...>>::label_map = {{&labels, Is}...};
struct LabelNotFound { };
template <class T, size_t N, Label&... labels>
struct Vector:VectorParent<Pack<labels...>, std::make_index_sequence<sizeof...(labels)>> {
static_assert(N == sizeof...(labels),
"the cound of labels should corespond to the number of elements of the vector");
using VectorParent<Pack<labels...>, std::make_index_sequence<sizeof...(labels)>>::label_map;
T t[N];
T &operator->*(Label& l) {
auto it = label_map.find(&l);
if (it == label_map.end())
throw LabelNotFound{};
return t[it->second];
}
};
int main() {
Vector<float,2,x,y> vec;
vec->*x = 10.0f;
printf("X: %.2f, Y: %.2f\n", vec->*x, vec->*y); // prints: X: 10.00, Y: 0.00
//vec->*w = 10.1f; //would throw an exception LabelNotFound
}
I'm trying to develop a function with different behaviour for arrays and pointers.
It could be achieved for classes by partial specialization, but it doesn't work on functions!
int i = 0;
some_func( &i ); // pointer
int arr[ 3 ] = { 0 };
some_func( arr ); // array
In second case inside of function some_func parameter type is int*, and there is no way to find out, that it's actually int[3].
On the other hand, if I use class template specialization, I'd have to specify array type explicitly:
template< typename T >
struct S
{
static void some_func( T t ) { ... }
};
template< typename T, size_t N >
struct S< T[ N ] >
{
static void some_func( T t[ N ] ) { ... }
};
// ...............
int arr[ 3 ] = { 0 };
S< int[ 3 ] >::some_func( arr ); // Works,
// but specifying type explicitly is not convenient
For now I've solved the problem with macro define (to be precise, I only need precise sizeof for arrays).
Is there any way to solve it without turning to the dark side of macro definitions?
Take the array by reference:
template< typename T >
void some_func( T *t ) { ... }
template< typename T, size_t N >
void some_func( T (&t)[ N ] ) { ... }
Here I use C++11 style programming in C++03 to do SFINAE and send my arrays at one overload, and non-arrays at another:
#include <iostream>
struct false_type { enum { value = false }; };
struct true_type { enum { value = true }; };
template<typename T>
struct is_array:false_type {};
template<typename T, std::size_t N>
struct is_array<T[N]>:true_type {};
template<bool b,typename T=void>
struct enable_if {};
template<typename T>
struct enable_if<true, T> { typedef T type; };
template<typename T>
typename enable_if< is_array<T>::value>::type some_func( T& array, int unused=0 )
{
std::cout << "array\n";
}
template<typename T>
typename enable_if< !is_array<T>::value>::type some_func( T const& not_array )
{
std::cout << "pointer\n";
}
int main() {
int x[3];
some_func( x );
int y;
some_func( &y );
}
I'm trying to implement a hypercubeclass, that is, multidimensional vectors.
I have a problem generalizing it. I'm able to make one for a three dimensional hypercube, but as mentioned, the problem is generalizing it. Could anyone help me? You should be able to write hypercube<4> w(5) to get 4 dimensions and 5 elements in each vector that is 5*5*5*5 elements in total.
Here is the code I have for the three dimensional version:
#include <vector>
using std::vector;
using namespace std;
template <int b>
class Hypercube {
public:
Hypercube(int a) : intvec(a){
for (int i = 0; i<a;i++) {
intvec[i].resize(a);
for (int j = 0;j<a;j++) {
intvec[i][j].resize(a);
}
}
}
vector<vector<int> >& operator[](int i) {
return intvec[i];
}
vector<vector<vector<int> > > intvec;
};
For this to work, you need recursive inheritence to provide the correct vector type and the initialization function. Both work recursively, for which I created a little helper struct called hcube_info:
// hypercube.h
#include <vector>
template<unsigned N>
struct hcube_info;
template<>
struct hcube_info<1>
{ // base version
typedef std::vector<int> type;
static type init(unsigned innerdim, int value = 0){
return type(innerdim, value);
}
};
template<unsigned N>
struct hcube_info
{ // recursive definition, N dimensions
private:
typedef hcube_info<N-1> base;
typedef typename base::type btype;
public:
typedef std::vector<btype> type;
static type init(unsigned innerdim, int value = 0){
return type(innerdim, base::init(innerdim, value));
}
};
As you can see, recursion all the way to the one dimensional base case. We also need to recursively initialize the vector to pass the inner dimension all the way through.
And now the real class, a nice interface around the hcube_info:
template<unsigned N>
struct hypercube
{
private:
typedef hcube_info<N> info;
typedef typename info::type vec_type;
public:
typedef typename vec_type::value_type value_type;
typedef typename vec_type::size_type size_type;
explicit hypercube(unsigned innerdim, unsigned value = 0)
: c(info::init(innerdim, value))
{
}
value_type& operator[](unsigned i){
return c[i];
}
size_type size() const{ return c.size(); }
private:
vec_type c;
};
Test program:
#include "hypercube.h"
#include <iostream>
int main(){
hypercube<4> c(5);
unsigned s = c.size() * // dim 1
c[0].size() * // dim 2
c[0][0].size() * // dim 3
c[0][0][0].size(); // dim 4
std::cout << s << '\n'; // outputs: 625 -> 5 * 5 * 5 * 5 -> 5^4
}
I would suggest something along those lines:
template <typename T, unsigned dim> class HQ {
std::vector<HQ<T,(dim-1)> > vector;
public:
HQ(unsigned size) : vector(size,HQ<T,(dim-1)>(size)) {}
};
template <typename T> class HQ<T,1> {
std::vector<T> vector;
public:
HQ(unsigned size) : vector(size,T()) {}
};
template <typename T> class HQ<T,0> {};
You can then implement your accessors for the first both templates as you wish. You can also make things a bit more simple and robust by allowing zero-dimensional matrices:
template <typename T, unsigned dim> class HQ {
std::vector<HQ<T,(dim-1)> > vector;
public:
HQ(unsigned size) : vector(size,HQ<T,(dim-1)>(size)) {}
};
template <typename T> class HQ<T,0> {
T data;
public:
HQ(unsigned size) : data() {}
};
I imagine an access operator would look something like this:
template <typename T, unsigned dim> HQ<T,(dim-1)>& HQ<T,dim>::operator[](unsigned i) {
return vector[i];
}
template <typename T, unsigned dim> HQ<T,(dim-1)> const& HQ<T,dim>::operator[](unsigned i) const {
return vector[i];
}
such that you can write
HQ<int,4> hq(5);
hq[1][4][2][0] = 77;