I want to create a function template that creates a list of all legal/valid instances of some class. The class itself is somehow informed about the values that each of its members can take. Function template:
template <typename T>
std::list<T> PossibleInstantiations();
Now, if SomeClass somehow contains information about legal instantiations of all its members (in below example, legal instantiations of i are 1,4,5 and legal instantiations of j are 1.0, 4.5), then
PossibleInstantiations<SomeClass>();
should yield a list containing elements {SomeClass(1,1.0), SomeClass(1,4.5), SomeClass(4,1.0), SomeClass(4,4.5), SomeClass(5,1.0), SomeClass(5,4.5)}.
Of course, adding extra elements (+ associated valid values) should automatically be handled by PossibleInstantiations.
Someclass would be implemented something like below. In what way should the plumbing be added to client classes (e.g. MyClass), and how should PossibleInstantiations be implemented?
class SomeClass
{
public:
int i;
static std::list<int> ValidValuesFori();
double j;
static std::list<double> ValidValuesForj();
SomeClass(int i, double j);
//int k;
//static std::list<int> ValidValuesFork(); //could be implemented at some later stage.
//Which would mean the constructor becomes:
//SomeClass(int i, int j, int k)
//...
//Extra wiring for pointing out that i and ValidValuesFori belong to each other,
//and perhaps for pointing out that i is the first element in the constructor, or so?
//..
};
static std::list<int> SomeClass::ValidValuesFori()
{
return std::list<int>{1, 4, 5};
//Other options:
//std::list<int> ValidValues;
//for (int i = 0; i < 1000; i++)
//{
// if (i % 3 == 0)
// ValidValues.push_back(i);
//}
//return ValidValues;
}
static std::list<double> SomeClass::ValidValuesForj()
{
return std::list<double>{1.0, 4.5};
}
SomeClass::SomeClass(int i, double j)//or other constructor
:i{ i }, j{ j } {}
Why make it hard if you can make it easy? You already say that SomeClass should know which values are allowed for its members. You could make this explicit by moving GetPossibleImplementations() to the class:
class SomeClass
{
public:
static std::vector<SomeClass> GetPossibleImplementations()
{
std::vector<SomeClass> values;
for (int i : ValidValuesFori())
for (double j : ValidValuesForj())
values.push_back(SomeClass(i, j));
return values;
}
// other methods
// [...]
}
Then you can still add the template function, if you need it:
template <typename T>
std::vector<T> GetPossibleImplementations()
{
return T::GetPossibleImplementations();
}
Moving the logic into the class has the following advantages:
Only the class knows which constructor args are valid, so it makes sense to have the logic there.
The cartesian product of valid argument values may not be sufficient for all cases. What if some value of i conflicts with some value of j?
You can still move some logic into helper functions, for example, the cartesian product.
There are situations where you cannot change the implementation of SomeClass and you need an external solution. Even in that case, I think you should keep the logic class-specific: Declare the generic function GetPossibleImplementations<T>() as above, but implement it only for the specific classes:
template <typename T>
std::vector<T> GetPossibleImplementations();
template <>
std::vector<SomeClass> GetPossibleImplementations<SomeClass>()
{
std::vector<SomeClass> values;
for (int i : SomeClass::ValidValuesFori())
for (double j : SomeClass::ValidValuesForj())
values.push_back(SomeClass(i, j));
return values;
}
The main differences between the two versions is that the first version yields a compile error if the template argument T does not support T::GetPossibleImplementations() and the second version yields a link error if GetPossibleImplementations<T> is not implemented.
With Cartesian product, we might do:
// cartesian_product_imp(f, v...) means
// "do `f` for each element of cartesian product of v..."
template<typename F>
void cartesian_product_imp(F f) {
f();
}
template<typename F, typename H, typename... Ts>
void cartesian_product_imp(F f, std::vector<H> const& h,
std::vector<Ts> const&... vs) {
for (H const& he: h) {
cartesian_product_imp([&](Ts const&... ts){
f(he, ts...);
}, vs...);
}
}
template <typename... Ts>
std::vector<std::tuple<Ts...>> cartesian_product(std::vector<Ts> const&... vs) {
std::vector<std::tuple<Ts...>> res;
cartesian_product_imp([&](Ts const&... ts){
res.emplace_back(ts...);
}, vs...);
return res;
}
template <typename T>
std::vector<T> PossibleInstantiations()
{
auto validValuesByArgs = T::ValidValuesForArgs();
auto validArgs =
std::apply([](const auto&... args){ return cartesian_product(args...); },
validValuesByArgs);
std::vector<T> res;
std::transform(validArgs.begin(), validArgs.end(),
std::back_inserter(res),
[](const auto& t){
return std::apply([](const auto&... args) { return T(args...); },
t);
});
return res;
}
With
class SomeClass
{
public:
int i;
double j;
const std::string s;
static std::tuple<std::vector<int>, std::vector<double>, std::vector<std::string>>
ValidValuesForArgs() { return {{1, 4, 5}, {1.1, 4.5}, {"foo", "bar"}}; }
SomeClass(int i, double j, const std::string& s) : i(i), j(j), s(s) {}
};
Demo
Related
Not sure if this can be done using templates but I want to give it a try.
I have a template class which takes any struct, stores it and returns it. Additionally, I want an interface that resets the struct's data whenever requested.
#define MYDEFAULT {1,2,3}
template < typename ITEM, ITEM Default>
class myClass{
public:
myClass(ITEM item) : _item(item) {}
const ITEM* get(){
return &_item;
}
void reset(){
_item = Default;
}
ITEM _item;
};
// Set to default when instantiated
myClass<myStruct, MYDEFAULT> ABC(MYDEFAULT);
Of course that's not working at all, but what I want to achieve is the replacement of Default in reset(). I mean it would work if _item would be of type int.
How can this be realized?
EDIT: I want something like this:
template <typename Y, Y T>
class myclass {
public:
void reset() {
xxx = T;
}
Y xxx{10};
};
void test()
{
myclass<int, 5> _myclass;
}
Initially xxx is 10 and after invoking reset it is 5. This works, so it seems it is not possible for POD or class types?
EDIT2: It seems it is all about non-type template-arguments. https://stackoverflow.com/a/2183121/221226
So there is no way around traits when using structs.
As a viable solution, you can use a trait class as shown in the following working example:
#include<cassert>
struct S {
int i;
};
template<typename T>
struct Traits {
static constexpr auto def() { return T{}; }
};
template<>
struct Traits<S> {
static constexpr auto def() { return S{42}; }
};
template <typename ITEM>
class myClass {
public:
myClass(): _item(Traits<ITEM>::def()) {}
myClass(ITEM item): _item(item) {}
const ITEM* get() {
return &_item;
}
void reset() {
_item = Traits<ITEM>::def();
}
ITEM _item;
};
int main() {
myClass<S> ABC{};
myClass<int> is;
assert((ABC.get()->i == 42));
assert((*is.get() == 0));
}
The basic trait uses the default constructor of the type ITEM.
You can then specialize it whenever you want a different defaulted value for a specific class.
The same can be accomplished even with a factory function as:
template<typename T>
constexpr auto def() { return T{}; }
template<>
constexpr auto def<S>() { return S{42}; }
Anyway, traits can easily provide more types and functions all at once.
You can maybe simulate it using a data structure with a data member of type std::array.
A minimal, working example follows:
#include<cstddef>
#include<array>
#include<cassert>
template<typename T, T... I>
struct S {
S(): arr{ I... } {}
S(const T (&val)[sizeof...(I)]) {
for(std::size_t i = 0; i < sizeof...(I); ++i) {
arr[i] = val[i];
}
}
const T * get() {
return arr.data();
}
void reset() {
arr = { I... };
}
private:
std::array<T, sizeof...(I)> arr;
};
int main() {
S<int, 1, 3, 5> s{{ 0, 1, 2 }};
assert(s.get()[1] == 1);
s.reset();
assert(s.get()[1] == 3);
}
I'm not sure I got exactly what you are asking for, but the interface in the example is close to the one in the question and the implementation details should not affect the users of your class.
I'm trying to write a math vector class. A first version goes like :
template <typename T, unsigned int n>
struct Vector {
Vector<T, n>(T t = T()) // default
{
for (int i = 0; i < n; i++)
{
data[i] = t;
}
}
Vector<T, n>(const Vector<T, n> &aVector)
{
for (unsigned int i = 0; i < n; i++)
{
data[i] = aVector.data[i];
}
}
Vector<T, n>(const T arr[n])
{
for (unsigned int i = 0; i < n; i++)
{
data[i] = arr[i];
}
}
T& operator[](unsigned int i);
const T& operator[](unsigned int i) const;
Vector<T, n>& operator=(const Vector<T, n> &aVector);
void normalise();
T data[n];
};
I also have operators (+, *, etc.) declared outside the class, as well as a couple of other classes.
Here's the thing though. For vectors of length 2, 3, 4 I'd like to have a constructor (or a function) that takes x,y (for Vec2), x,y,z or x,y,z,w as parameters.
However, it seems that you can't make specialised constructors for this purpose. How should I proceed in that case ? Do I have to completely specialise three cases ? Wouldn't that imply that I have to rewrite chunks of code ?
I also have a similar Matrix class ( Matrix), and I'm pretty sure I'll need some constructors for rotation, translation, scaling, etc. I'm assuming I'll need to overcome a similar problem.
If you see
I also have operators (+, *, etc.) declared outside the class, as well as a couple of other functions (dot, cross, etc.).
Here's the thing though. For vectors of length 2, 3, 4 I'd like to have a constructor (or a function) that takes x,y (for Vec2), x,y,z or x,y,z,w as parameters.
However, it seems that you can't make specialised constructors for this purpose. How should I proceed in that case ? Do I have to completely specialise three cases ? Wouldn't that imply that I have to rewrite chunks of code ?
I also have a similar Matrix class ( Matrix), and I'm pretty sure I'll need some constructors for rotation, translation, scaling, etc. I'm assuming I'll need to overcome a similar problem.
If you see anything in the code that seems wrong to you, feel free to point it out by the way.
EDIT : In case I was not clear enough, the arrays are meant to be one-dimensional, and all of its components are of the same type. The specialisations are for arrays with 2, 3 and 4 elements.
You may utilize a variadic template:
#include <chrono>
#include <future>
#include <iostream>
#include <stdexcept>
template<typename T, unsigned int n>
struct Vector
{
// Note: We need x and y:
// The default (in the question) is a constructor taking a single argument.
template <typename ... Args>
Vector(T x, T y, Args ... args)
{
static_assert(sizeof ... (Args) == n - 2, "Invalid number of arguments");
auto initializer_list = { x, y, std::forward<Args>(args)... };
std::copy(initializer_list.begin(), initializer_list.end(), data);
}
T data[n];
};
template<typename T, unsigned int n>
void print(const Vector<T, n>& v) {
for(unsigned i = 0; i < n; ++i)
std::cout << v.data[i] << ' ';
std::cout << '\n';
}
int main()
{
Vector<int, 2> v2(1, 2);
Vector<int, 3> v3(1, 2, 3);
Vector<int, 4> v4(1, 2, 3, 4);
print(v2);
print(v3);
print(v4);
// Invalid number of arguments
// Vector<int, 3> e2(1, 2);
// Invalid number of arguments
// Vector<int, 3> e4(1, 2, 3, 4);
return 0;
}
Personally, I would declare different classes for each vector. Vec2<T1, T2>, Vec3<T1, T2, T3>, and Vec4<T1, T2, T3, T4>. Make each Vec* class publicly inherit a un-templated base class Vector, and then make a static function create in Vector with an overload for each Vec* type that will be responsible for creating them. Pseudo-example for Vec3:
template<T1, T2, T3> static std::shared_ptr<Vector> create(T1 a1, T2 a2, T3 a3)
{
return new Vec3<T1, T2, T3>(a1, a2, a3);
}
auto vec = Vector::create<int, int, int>(1, 2, 3);
variadic template and SFINAE may solve that.
but I think the simpler would be to inherit from (specialized) helper
template <typename T, unsigned int n>
struct VectorHelper<T, n>
{
T data[n];
};
template <typename T>
struct VectorHelper<T, 2>
{
VectorHelper(T x, T y) : {data[0] = x; data[1] = y;}
T data[2];
};
template <typename T>
struct VectorHelper<T, 3>
{
VectorHelper(T x, T y, T z) : {data[0] = x; data[1] = y; data[2] = z}
T data[3];
};
template <typename T, unsigned int n>
struct Vector : private VectorHelper<T, n>
{
using VectorHelper<T, n>::VectorHelper; // use base constructor(s)
// your previous implementation without `data` (as member of base)
};
I made an N-dimensional structure with vectors and templates:
//----------------N-dimensional vector--------------------------------
template<int dim,typename T> class n_dim_vector {
public:
typedef std::vector<typename n_dim_vector<dim - 1, T>::vector> vector;
};
template<typename T> class n_dim_vector <0, T> {
public:
typedef T vector;
};
It can be instatiaated with different dimnsion-counts and is prt of a class that represent a search space.
template<int dim, typename T> class n_dim_ssc {
private:
typename n_dim_vector<dim, T>::vector searchspace;
};
My problem: I cannot get operator[] right to access searchspace properly, specifically the return type.
I tried:
template<typename V> std::vector<V>& operator[](unsigned i) {
return searchspace[i];
}
T& operator[](unsigned i) {
return searchspace[i];
}
at first, thinking the compiler would derive typename V as whatever type searchspace contained at all but the last level. Thats what T& operator[](unsigned i) was for.
But alas, doen't work this way. And I cannot work out how it would
EDIT Don't fear, I do not access empty memory, the structure is initialized and filled, I just didn't include the code for clarity's sake.
Also, I don't intend to access it with a single integer, I wanted to use searchspace[i][j]..[k]
The way to let compiler deduces the return type is auto:
In C++14:
auto operator[](unsigned i) { return searchspace[i]; }
In C++11:
auto operator[](unsigned i) -> decltype(searchspace[i]) { return searchspace[i]; }
I'm answering to your comment
Feel free to recommend something better, I'd appreciate it.
The following code shows one way to handle the multidimensional vector at once, i.e. non-recursively. It could be improved in several ways which I didn't consider for now (for instance, I wouldn't want to use and pass that many arrays but rather use variadic parameter lists. This however requires much more and more diffcult code, so I'll let it be.)
#include <numeric>
template<size_t Dim, typename T>
struct MultiDimVector
{
std::array<size_t, Dim> Ndim;
std::array<size_t, Dim> stride;
std::vector<T> container;
MultiDimVector(std::array<size_t, Dim> const& _Ndim) : Ndim(_Ndim), container(size())
{
stride[0] = 1;
for (size_t i = 1; i<Dim; ++i)
{
stride[i] = stride[i - 1] * Ndim[i - 1];
}
}
size_t size() const
{
return std::accumulate(Ndim.begin(), Ndim.end(), 1, std::multiplies<size_t>());
}
size_t get_index(std::array<size_t, Dim> const& indices) const
{
//here one could also use some STL algorithm ...
size_t ret = 0;
for (size_t i = 0; i<Dim; ++i)
{
ret += stride[i] * indices[i];
}
return ret;
}
T const& operator()(std::array<size_t, Dim> const& indices) const
{
return container[get_index(indices)];
}
};
You can use it like
MultiDimVector<3, double> v({ 3, 2, 5 }); //initialize vector of dimension 3x2x5
auto a = v({0,1,0}); //get element 0,1,0
But as I wrote, the curly brackets suck, so I'd rewrite the whole thing using variadic templates.
The problem with your approach is that you're not initializing any memory inside the vector and just trying to return non-existent memory spots. Something on the line of the following (WARNING: uncleaned and unrefactored code ahead):
#include <iostream>
#include <vector>
template<int dim,typename T> class n_dim_vector {
public:
typedef std::vector<typename n_dim_vector<dim - 1, T>::vector> vector;
};
template<typename T> class n_dim_vector <0, T> {
public:
typedef T vector;
};
template<int dim, typename T> class n_dim_ssc {
public:
typename n_dim_vector<dim, T>::vector searchspace;
n_dim_ssc() {}
n_dim_ssc(typename n_dim_vector<dim, T>::vector space) : searchspace(space) {}
n_dim_ssc<dim-1, T> operator[](std::size_t i) {
if(searchspace.size() < ++i)
searchspace.resize(i);
return n_dim_ssc<dim-1, T>(searchspace[--i]);
}
typename n_dim_vector<dim, T>::vector get() {
return searchspace;
}
};
template<typename T> class n_dim_ssc<0,T> {
public:
typename n_dim_vector<0, T>::vector searchspace;
n_dim_ssc() {}
n_dim_ssc(typename n_dim_vector<0, T>::vector space) : searchspace(space) {}
typename n_dim_vector<0, T>::vector get() {
return searchspace;
}
};
int main(int argc, char** argv) {
n_dim_ssc<0, int> ea;
int a = ea.get();
n_dim_ssc<1, int> ea2;
auto dd2 = ea2[0].get();
n_dim_ssc<2, int> ea3;
auto dd3 = ea3[0][0].get();
}
Try it out
will work with an accessor method (you can modify this as you want).
Anyway I strongly have to agree with Kerrek: a contiguous memory space accessed in a multi-dimensional array fashion will both prove to be faster and definitely more maintainable/easier to use and read.
Is it possible to call std::sort() on a std::vector of objects in such a way that we can specify which member will be used to compare the objects, but without having to implement a seperate compare function for each member. We can assume that each member that we want to sort by will have the < operator defined. If not, what is the best approach when we want to be able to sort a container of objects by many different criteria.
You can have a comparison object that has a flag indicating which member to sort on.
class Comparo
{
int m_field;
public:
Comparo(int field) : m_field(field) { }
bool operator()(const MyClass & Left, const MyClass & right)
{
switch (m_field)
{
case 0:
return left.A < right.A;
case 1:
return left.B < right.B;
}
}
};
std::vector<MyClass> vec = FillMyVector();
std::sort(vec.begin(), vec.end(), Comparo(0)); // sorts on field A
std::sort(vec.begin(), vec.end(), Comparo(1)); // sorts on field B
Here's something that does a lexicographical comparison using arbitrarily many members of any class. Needs C++14 for variadic templates and compile-time integer sequences. You can implement compile-time integer sequences yourself if you have C++11.
#include <tuple>
#include <utility> // for make_index_sequence
template<class T, typename... types>
struct member_comparer {
member_comparer(types T::*... args) : ptrs(args...) { }
bool operator()(const T& t1, const T& t2) const {
return do_compare(t1, t2, std::make_index_sequence<sizeof...(types)>());
}
private:
template<size_t... indices>
bool do_compare(const T& t1, const T& t2, std::index_sequence<indices...> ) const {
return std::tie(t1.*std::get<indices>(ptrs)...) <
std::tie(t2.*std::get<indices>(ptrs)...);
}
std::tuple<types T::* ...> ptrs;
};
template<class T, typename... types>
auto make_member_comparer(types T::*... args) {
return member_comparer<T, types...>(args...);
}
You use it like:
struct A {
int x;
double y;
float z;
};
auto compare_x_only = make_member_comparer(&A::x);
auto compare_y_then_x = make_member_comparer(&A::y, &A::x);
Demo.
The following simple code pattern is very common in graphics programming.
It creates an array of layers and loops over them.
struct Layer
{
int n;
void operator()(float value)
{
}
};
struct AnotherLayer
{
int n;
int m;
void operator()(float value)
{
}
};
void process_layers(Layer_t* layer, size_t size, float value)
{
for (size_t n = 0; n < size; ++n)
layer[n](value);
}
Layer a = {1};
Layer b = {2};
AnotherLayer c = {2,3};
typedef std::function < void (float) > Layer_t;
Layer_t layers [] = {a,b,c};
process_layers(layers, sizeof(layers)/sizeof(Layer), 100);
I would like to convert this to use varadic templates in c++11. Any ideas how I could do this. This is what I would like it to look like. Any ideas? Is this even possible?
template <int n>
struct Layer
{
void operator()(float value)
{
}
};
template <int n, int m>
struct AnotherLayer
{
void operator()(float value)
{
}
};
template <typename Layer1, typename Layer2, ...>
struct Layers //process_layers
{
void operator()(float value)
{
for (size_t n = 0; n < SIZEOF(Layer1,Layer2,...); ++n)
Layer[N]()(value);
}
};
Then I could do this.
typedef Layers<Layer<1>, Layer<2>, AnotherLayer<3,8> > funky_layer_t;
typedef Layers<Layer<4>, Layer<5>, Layer<5>, AnotherLayer<6,7> > standard_layer_t;
typedef Layers<funky_layer_t, standard_layer_t> awesome_layer_t;
awesome_layer_t()(100);
Note: with the second approach, all paramaters to construct layers are known at compile time.
The example you give is very simple to re-do with variadic templates.
template<typename Func> void process(Func &&f) {} // base case for zero items
// overload for at least one item
template<typename Func, typename FirstItem, typename... Items>
void process(Func &&f, FirstItem &&fi, Items &&...is) {
std::forward<Func>(f)(std::forward<FirstItem>(fi)); // f(fi);
process(std::forward<Func>(f), std::forward<Items>(is)...); // process(f,is...);
}
Layer a = {1};
Layer b = {2};
Layer c = {3};
process([](Layer &l){ l(100); },
a, b, c);
Also notice that this avoids all the unnecessary copies in the original. (Though of course you could also avoid them just by doing Layer layers[] = {{1},{2},{3}};)
I'm not exactly sure how your later comments and code are related to running an operation over a collection of layers.
What exactly is the computation you want to perform at compile-time?
To adjust for the new example the process() does not need to change at all, you only need to create a functor that can handle each type. (polymorphic lambdas would help here, but we'll have to make due with an explicit functor type)
Layer a = {1};
Layer b = {2};
AnotherLayer c = {2,3};
struct TheOperation {
template<typename T>
void operator() (T &t) {
t(100);
}
};
process(TheOperation(),
a, b, c);
Here's your awesome_layer_t transcribed to correct variadic template syntax, but I still don't see what you want to accomplish, so I can't say if this is a good way to do it or not. This doesn't actually call the operator()s at compile-time, it only arranges to have a bunch of objects default constructed at runtime and then operator() called, again, at runtime.
template <int n>
struct Layer
{
int operator()(float value)
{
std::printf("L %d %e\n",n,value);
return 0;
}
};
template <int n, int m>
struct AnotherLayer
{
int operator()(float value)
{
std::printf("AL %d %d %e\n",n,m,value);
return 0;
}
};
template <typename... Ls>
struct Layers //process_layers
{
int operator()(float value)
{
struct Tmp {
void operator() (...) {}
};
Tmp()( Ls()(value)...);
return 0;
}
};
typedef Layers<Layer<1>, Layer<2>, AnotherLayer<3,8> > funky_layer_t;
typedef Layers<Layer<4>, Layer<5>, Layer<5>, AnotherLayer<6,7> > standard_layer_t;
typedef Layers<funky_layer_t, standard_layer_t> awesome_layer_t;
int main() {
awesome_layer_t()(100);
}
I believe that you can do this using normal function templates as follows:
/* Base case: If you have no layers to apply, do nothing. */
void executeLayers() {
// Deliberately empty.
}
/* Recursive step: If you have at least one layer, apply it, then apply the
* remaining layers.
*/
template <typename Head, typename... Tail>
void executeLayers(Head head, Tail... tail) {
head(); // Execute the first layer
executeLayers(tail); // Execute the remaining layers
}
You could then do something like this:
executeLayers(layer1, layer2, layer3, layer4, layer5);
Hope this helps!