Related
I'm working on a set of classes. My Function class will take a Functor class which stores a function pointer to some defined function which has an operator that will invoke the function call from the function pointer. It uses a Limit class that currently takes <int,int> for its upper and lower bounds. It has nothing but static constexpr functions to return the bounds and to calculate the number of elements between those bounds. If the lower bounds = 1 and upper bounds = 5 it will generate 5 for the number of elements to be evaluated for that function...
Here is what I'm doing with these classes:
First I declare a function such as f(x) = x, f(x) = x^2, or f(x) = cos(x), etc.
Then I instantiate a Functor object based on the above function(s) parameter types both for the return and for its parameter-argument types...
Next, I assign the function to my Functor class's member variable.
Then I instantiate a Function object giving it the data-type and the Lower & Upper limits for the range of the function.
The Function class upon construction automatically generates the data points of that function from [lower,upper] and stores the generated values in its internal array.
The Function class also contains an operator that will allow the user to get any value from any given input.
Pseudo Example:
f(x) = x^2;
Functor<T,T> functor;
functor.member = &f(x);
Function<T,Lower,Upper,T> function(functor);
// If T=int, Lower = -4, and Upper = 4 then the internal data set will be
// (-4,16) (-3,9), (-2,4), (-1,1), (0,0), (1,1), (2,4), (3,9), (4,16)
// The user can also use it's operator to call function(9) and it will return 81
Here is my working program that is generating datasets of values from my classes using various functions:
main.cpp
#include <cmath>
#include <exception>
#include <iostream>
#include "Function.h"
int main() {
try {
pipes::Functor<int, int> functor1;
functor1.FuncPtr = □
pipes::Function<int, -10, 10, int> func1( functor1 );
auto data1{ func1.data() };
for (auto& p : data1)
std::cout << '(' << p.first << ',' << p.second << ")\n";
std::cout << '\n';
std::cout << "f(25) = " << func1(25) << "\n\n";
pipes::Functor<int, int> functor2;
functor2.FuncPtr = &linear;
pipes::Function<int, -10, 10, int> func2(functor2);
auto data2{ func2.data() };
for (auto& p : data2)
std::cout << '(' << p.first << ',' << p.second << ")\n";
std::cout << '\n';
std::cout << "f(25) = " << func2(25) << "\n\n";
pipes::Functor<double, double> functor3;
functor3.FuncPtr = &cosine;
pipes::Function<double, -7, 7, double> func3(functor3);
auto data3{ func3.data() };
for (auto& p : data3)
std::cout << '(' << p.first << ',' << p.second << ")\n";
std::cout << '\n';
std::cout << "f(25) = " << func3(25) << "\n\n";
}
catch (const std::exception& e) {
std::cerr << e.what() << "\n\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Function.h
#pragma once
#include <array>
namespace pipes {
template<typename Ret, typename... Args>
struct Functor {
Ret(*FuncPtr)(Args...);
Ret operator()(Args... args) { return FuncPtr(args...); }
};
template<int Lower, int Upper>
class Limits {
public:
static constexpr unsigned lower_bound() { return Lower; }
static constexpr unsigned upper_bound() { return Upper; }
static constexpr unsigned element_count() { return (Upper - Lower + 1); }
};
template<typename T, int Lower, int Upper, typename... Args>
class Function {
std::array<std::pair<T, T>, Limits<Lower,Upper>::element_count()> data_points_;
Functor<T,Args...> functor_;
public:
Function(Functor<T,Args...> func) {
functor_ = func;
for (unsigned i = 0; i < Limits<Lower,Upper>::element_count(); i++) {
data_points_[i].first = ((T)i + (T)Lower);
data_points_[i].second = functor_(data_points_[i].first);
}
}
T operator()(Args... args) const {
return functor_.FuncPtr(args...);
}
constexpr auto lower() const { return Lower; }
constexpr auto upper() const { return Upper; }
constexpr auto count() const { return Limits<Lower,Upper>::element_count(); }
constexpr auto data() const { return data_points_; }
};
} // namespace pipes
When I run the program it is generating this output which appears to be correct:
Output
(-10,100)
(-9,81)
(-8,64)
(-7,49)
(-6,36)
(-5,25)
(-4,16)
(-3,9)
(-2,4)
(-1,1)
(0,0)
(1,1)
(2,4)
(3,9)
(4,16)
(5,25)
(6,36)
(7,49)
(8,64)
(9,81)
(10,100)
f(25) = 625
(-10,-10)
(-9,-9)
(-8,-8)
(-7,-7)
(-6,-6)
(-5,-5)
(-4,-4)
(-3,-3)
(-2,-2)
(-1,-1)
(0,0)
(1,1)
(2,2)
(3,3)
(4,4)
(5,5)
(6,6)
(7,7)
(8,8)
(9,9)
(10,10)
f(25) = 25
(-7,0.753902)
(-6,0.96017)
(-5,0.283662)
(-4,-0.653644)
(-3,-0.989992)
(-2,-0.416147)
(-1,0.540302)
(0,1)
(1,0.540302)
(2,-0.416147)
(3,-0.989992)
(4,-0.653644)
(5,0.283662)
(6,0.96017)
(7,0.753902)
f(25) = 0.991203
And now for my question where this becomes the tricky part...
With my code currently the way it is, everything is fine as long as my bounds [-a,b] are of an integral type...
Let's suppose on my last example such as with cos, what if I want to have my bounds from [-2pi,2pi] where the lower and upper limits are of floating-point types...
The Issue:
Currently in C++ this is non-standard and in most cases won't compile:
template<float val> // or template<double>
struct foo() {
constexpr float operator()() {
return val;
}
};
And the above prevents me from doing something like this:
constexpr double PI{ 6.28318531 };
pipes::Functor<double, double> functor3;
functor3.FuncPtr = &cosine;
pipes::Function<double, -PI, PI, double> func3(functor3);
auto data3{ func3.data() };
for (auto& p : data3)
std::cout << '(' << p.first << ',' << p.second << ")\n";
std::cout << '\n';
std::cout << "f(25) = " << func3(25) << "\n\n";
So if I want to be able to support floating-point types for my intervals of my Limits or Range class... What kind of alternative would there be if such a thing is currently possible in c++? Or would I just have to simply restructure the way my class templates are designed?
If the above is possible in some way during compile time via templates and constexpr semantics, then there is another issue that arises that will have to be taken into consideration and that would be the stepping interval for use with floating-point types to know how many data points there will be within the dataset... (basically calculating dx based on some stepping value which would be defined by the user, for example: (0.1, 0.001, etc...) and the number of data points would be calculated by the number of these divisions between [lower, upper]... However, if the stepping value is known at compile-time, then calculating the divisions should be simple enough... that's not a major concern. The bigger concern is being able to express floating-point constants at compile time for template evaluation...
Currently, with the way my code is with its design, I have hit a limit on its functionality... I'm not sure how to provide a similar interface to support a floating-point range that can be calculated and generated at compile time! Any bit of help or suggestions is welcomed!
I think the closest you can get to a construct like yours is:
#include <iostream>
#include <array>
constexpr const double PI_2{ 6.28318531 };
template<double const &lower, double const &upper>
void foo() {
static_assert(lower<upper, "invalid lower and upper value");
constexpr size_t size = (upper-lower);
std::array<int, size> test;
std::cout << lower << " " << upper << " " << test.size() << std::endl;
}
template<double const &V>
struct neg {
static constexpr double value = -V;
};
int main()
{
foo<neg<PI_2>::value, PI_2>();
return 0;
}
If you can always specify the type as first template argument you could have something like this:
template<typename T, T const &lower, T const &upper>
void foo() {
std::cout << lower << " " << upper << std::endl;
}
I didn't fully think it through, how to get the floating-point part and the other together, but I think it should be possible.
In modern C++ and how templates are currently designed, I had to slightly restructure my code. It's forcing me to have to use std::vector instead of std::array, because we can't use floating-point types as constant template arguments... So I ended up having to change two of my classes... I had to change my Limits class, and my Function class.
My Limits class now accepts a Type instead of constant-integral-type and it stores 3 member variables. It also has a default constructor and a user constructor. The functions are now just constexpr instead of being static.
My Function class now stores a Limits class object and data_points_ is no longer an std::array as it is now std::vector. It's constructor now also takes in a Limits object.
I had also taken into account for the step size for floating-point ranges.
Here is what my modified code looks like with its given output:
main.cpp
#include <cmath>
#include <iostream>
#include <exception>
#include "Function.h"
constexpr int square(int x) {
return x * x;
}
constexpr int linear(int x) {
return x;
}
double cosine(double x) {
return cos(x);
}
//template<float val>
struct foo {
float operator()(float val) { return val; }
};
int main() {
try {
pipes::Functor<int, int> functor1;
pipes::Limits<int> limit1(-10, 10, 1);
functor1.FuncPtr = □
pipes::Function<int, int, int> func1( limit1, functor1 );
auto data1{ func1.data() };
for (auto& p : data1)
std::cout << '(' << p.first << ',' << p.second << ")\n";
std::cout << '\n';
std::cout << "f(25) = " << func1(25) << "\n\n";
pipes::Functor<int,int> functor2;
pipes::Limits<int> limit2(-10, 10, 1);
functor2.FuncPtr = &linear;
pipes::Function<int, int, int> func2(limit2, functor2);
auto data2{ func2.data() };
for (auto& p : data2)
std::cout << '(' << p.first << ',' << p.second << ")\n";
std::cout << '\n';
std::cout << "f(25) = " << func2(25) << "\n\n";
constexpr double PI{ 6.28318531 };
pipes::Functor<double, double> functor3;
pipes::Limits<double> limits3( (-PI), PI, 0.1);
functor3.FuncPtr = &cosine;
pipes::Function<double, double, double> func3(limits3, functor3);
auto data3{ func3.data() };
for (auto& p : data3)
std::cout << '(' << p.first << ',' << p.second << ")\n";
std::cout << '\n';
std::cout << "f(25) = " << func3(25) << "\n\n";
}
catch (const std::exception& e) {
std::cerr << e.what() << "\n\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Function.h
#pragma once
#include <vector>
namespace pipes {
template<typename Ret, typename... Args>
struct Functor {
Ret(*FuncPtr)(Args...);
Ret operator()(Args... args) { return FuncPtr(args...); }
};
template<typename Ty>
class Limits {
private:
Ty Lower;
Ty Upper;
Ty Step;
public:
Limits() {}
Limits(Ty lower, Ty upper, Ty step) : Lower{ lower }, Upper{ upper }, Step{ step } {}
constexpr Ty lower_bound() { return Lower; }
constexpr Ty upper_bound() { return Upper; }
constexpr Ty step_size() { return Step; }
constexpr unsigned element_count() { return (unsigned)((Upper - Lower + 1)/Step); }
};
template<typename LimT, typename FuncT, typename... Args>
class Function {
Limits<LimT> limits_;
Functor<FuncT, Args...> functor_;
std::vector<std::pair<FuncT, FuncT>> data_points_;
public:
Function(Limits<LimT> limits, Functor<FuncT,Args...> func) {
limits_ = limits;
functor_ = func;
data_points_.resize( limits_.element_count() );
for (unsigned i = 0; i < limits_.element_count(); i++) {
auto x = limits_.lower_bound() + (i * limits_.step_size());
data_points_[i].first = (x);
data_points_[i].second = functor_(x);
}
}
FuncT operator()(Args... args) const {
return functor_.FuncPtr(args...);
}
constexpr auto lower() const { return limits_.lower_bound(); }
constexpr auto upper() const { return limits_.upper_bound(); }
constexpr auto count() const { return limits_.element_count(); }
constexpr auto step() const { return limits_.step_size(); }
constexpr auto data() const { return data_points_; }
};
} // namespace pipes
Output
(-10,100)
(-9,81)
(-8,64)
(-7,49)
(-6,36)
(-5,25)
(-4,16)
(-3,9)
(-2,4)
(-1,1)
(0,0)
(1,1)
(2,4)
(3,9)
(4,16)
(5,25)
(6,36)
(7,49)
(8,64)
(9,81)
(10,100)
f(25) = 625
(-10,-10)
(-9,-9)
(-8,-8)
(-7,-7)
(-6,-6)
(-5,-5)
(-4,-4)
(-3,-3)
(-2,-2)
(-1,-1)
(0,0)
(1,1)
(2,2)
(3,3)
(4,4)
(5,5)
(6,6)
(7,7)
(8,8)
(9,9)
(10,10)
f(25) = 25
(-6.28319,1)
(-6.18319,0.995004)
(-6.08319,0.980067)
(-5.98319,0.955336)
(-5.88319,0.921061)
(-5.78319,0.877583)
(-5.68319,0.825336)
(-5.58319,0.764842)
(-5.48319,0.696707)
(-5.38319,0.62161)
(-5.28319,0.540302)
(-5.18319,0.453596)
(-5.08319,0.362358)
(-4.98319,0.267499)
(-4.88319,0.169967)
(-4.78319,0.0707372)
(-4.68319,-0.0291995)
(-4.58319,-0.128844)
(-4.48319,-0.227202)
(-4.38319,-0.32329)
(-4.28319,-0.416147)
(-4.18319,-0.504846)
(-4.08319,-0.588501)
(-3.98319,-0.666276)
(-3.88319,-0.737394)
(-3.78319,-0.801144)
(-3.68319,-0.856889)
(-3.58319,-0.904072)
(-3.48319,-0.942222)
(-3.38319,-0.970958)
(-3.28319,-0.989992)
(-3.18319,-0.999135)
(-3.08319,-0.998295)
(-2.98319,-0.98748)
(-2.88319,-0.966798)
(-2.78319,-0.936457)
(-2.68319,-0.896758)
(-2.58319,-0.8481)
(-2.48319,-0.790968)
(-2.38319,-0.725932)
(-2.28319,-0.653644)
(-2.18319,-0.574824)
(-2.08319,-0.490261)
(-1.98319,-0.400799)
(-1.88319,-0.307333)
(-1.78319,-0.210796)
(-1.68319,-0.112153)
(-1.58319,-0.0123887)
(-1.48319,0.087499)
(-1.38319,0.186512)
(-1.28319,0.283662)
(-1.18319,0.377978)
(-1.08319,0.468517)
(-0.983185,0.554374)
(-0.883185,0.634693)
(-0.783185,0.70867)
(-0.683185,0.775566)
(-0.583185,0.834713)
(-0.483185,0.88552)
(-0.383185,0.927478)
(-0.283185,0.96017)
(-0.183185,0.983268)
(-0.0831853,0.996542)
(0.0168147,0.999859)
(0.116815,0.993185)
(0.216815,0.976588)
(0.316815,0.950233)
(0.416815,0.914383)
(0.516815,0.869397)
(0.616815,0.815725)
(0.716815,0.753902)
(0.816815,0.684547)
(0.916815,0.608351)
(1.01681,0.526078)
(1.11681,0.438547)
(1.21681,0.346635)
(1.31681,0.25126)
(1.41681,0.153374)
(1.51681,0.0539554)
(1.61681,-0.0460021)
(1.71681,-0.1455)
(1.81681,-0.243544)
(1.91681,-0.339155)
(2.01681,-0.431377)
(2.11681,-0.519289)
(2.21681,-0.602012)
(2.31681,-0.67872)
(2.41681,-0.748647)
(2.51681,-0.811093)
(2.61681,-0.865435)
(2.71681,-0.91113)
(2.81681,-0.947722)
(2.91681,-0.974844)
(3.01681,-0.992225)
(3.11681,-0.999693)
(3.21681,-0.997172)
(3.31681,-0.984688)
(3.41681,-0.962365)
(3.51681,-0.930426)
(3.61681,-0.889191)
(3.71681,-0.839072)
(3.81681,-0.780568)
(3.91681,-0.714266)
(4.01681,-0.640826)
(4.11681,-0.560984)
(4.21681,-0.475537)
(4.31681,-0.385338)
(4.41681,-0.291289)
(4.51681,-0.19433)
(4.61681,-0.0954289)
(4.71681,0.0044257)
(4.81681,0.104236)
(4.91681,0.203005)
(5.01681,0.299745)
(5.11681,0.393491)
(5.21681,0.483305)
(5.31681,0.56829)
(5.41681,0.647596)
(5.51681,0.720432)
(5.61681,0.78607)
(5.71681,0.843854)
(5.81681,0.893206)
(5.91681,0.933634)
(6.01681,0.964733)
(6.11681,0.986192)
(6.21681,0.997798)
(6.31681,0.999435)
(6.41681,0.991085)
(6.51681,0.972833)
(6.61681,0.94486)
(6.71681,0.907447)
(6.81681,0.860967)
(6.91681,0.805884)
(7.01681,0.742749)
(7.11681,0.672193)
f(25) = 0.991203
This is giving me the behavior that I want, however, I was trying to do the same thing using array... I'm guessing until C++ supports floating-point-constants as template arguments I'm going to have to settle with std::vector using heap allocations, instead of std::array and stack-cache friendly containers...
I am trying to use boost proto to lazily evaluate expressions, what I want to do is be able to give different behaviours to tags like +, -, function etc.
function(
terminal(8functionILi2EE)
, plus(
multiplies(
terminal(6tensorILi0EE)
, terminal(6tensorILi1EE)
)
, multiplies(
terminal(6tensorILi2EE)
, terminal(6tensorILi3EE)
)
)
)
For a tree like above, I want to be able to specify how each of the tree nodes should behave.
For eg.
struct context : proto::callable_context< context const >
{
// Values to replace the tensors
std::vector<double> args;
// Define the result type of the zero.
// (This makes the zero_context "callable".)
typedef double result_type;
// Handle the tensors:
template<int I>
double operator()(proto::tag::terminal, tensor<I>) const
{
std::cout << this->args[I] << std::endl;
return this->args[I];
}
template<int I>
void operator()(proto::tag::plus) const
{
std::cout << " + " << std::endl;
}
};
When I do
double result = (_tensorA + _tensorB)(10, 20);
I expect my output to be
10
+
20
But it's just
10
20
Any help would be deeply appreciated! :)
template<int I>
void operator()(proto::tag::plus) const
{
std::cout << " + " << std::endl;
}
The template argument I is non-deducible, so the overload will never be applicable. Drop the template argument:
void operator()(proto::tag::plus) const
{
std::cout << " + " << std::endl;
}
HOWEVER What you really want is intercept the binary operator. Well. Note it's binary. So it has two args:
template<size_t I, size_t J>
void operator()(proto::tag::plus, proto::literal<tensor<I>>&, proto::literal<tensor<J>>&) const {
std::cout << " + " << std::endl;
}
Live On Coliru
However, this blocks further evaluation of the expression tree. Not what you wanted, right. So, let's do a simplisitic re-implementation:
template<size_t I, size_t J>
double operator()(proto::tag::plus, proto::literal<tensor<I>>& a, proto::literal<tensor<J>>& b) const {
auto va = (*this)(proto::tag::terminal{}, a.get());
std::cout << " + " << std::endl;
auto vb = (*this)(proto::tag::terminal{}, b.get());
return va + vb;
}
Live On Coliru
Generic, please
However, something tells me you wanted generic expressions. So t1 + (t2 + t3) should also work, but (t2 + t3) is no literal...
Let's simplify by delegating:
template<typename A, typename B>
double operator()(proto::tag::plus, A& a, A& b) const {
auto va = proto::eval(a, *this);
std::cout << " + " << std::endl;
auto vb = proto::eval(b, *this);
return va + vb;
}
Full Sample
Live On Coliru
#include <boost/proto/proto.hpp>
#include <vector>
namespace proto = boost::proto;
template <size_t N> struct tensor { };
template <size_t N, size_t M> tensor<N+M> operator+(tensor<N>, tensor<M>) { return {}; }
struct context : proto::callable_context< context const >
{
using base_type = proto::callable_context<context const>;
// Values to replace the tensors
std::vector<double> args { 0, 111, 222, 333 };
// Define the result type of the zero.
// (This makes the zero_context "callable".)
typedef double result_type;
// Handle the tensors:
template<size_t I>
double operator()(proto::tag::terminal, tensor<I>) const
{
std::cout << this->args[I] << std::endl;
return this->args[I];
}
template<typename A, typename B>
double operator()(proto::tag::plus, A& a, B& b) const {
auto va = proto::eval(a, *this);
std::cout << " + " << std::endl;
auto vb = proto::eval(b, *this);
return va + vb;
}
};
int main() {
proto::literal<tensor<1> > t1;
proto::literal<tensor<2> > t2;
proto::literal<tensor<3> > t3;
auto r = proto::eval(t1 + (t2 + t3), context());
std::cout << "eval(t1 + (t2 + t3)) = " << r << "\n";
}
Prints
111
+
222
+
333
eval(t1 + (t2 + t3)) = 666
Not sure if it's possible for more later version of c++. (I can't figure out using traditional c++ to achieve the following behaviofgr.)
For example,
If I have an array defined like this:
In the header file
struct Def {
static const int N = 5;
static const double data[N];
};
In its cpp
const double Def::data[Def::N] = {0,1,2,3,4};
Is it possible to have a template get_subarray such that
get_subarray<Def,2,0>::data will be an array of content {0,2,4}
get_subarray<Def,2,1>::data will be an array of content {1,3}
where
template<typename T, int M, int m>
struct get_phase {
// some code for the array variable data which will
// extract element from T::data for every M sample offset by index m
};
As mentioned in the comments, the OP is interested also in C++14 based solutions.
Here is one of them:
#include<functional>
#include<cstddef>
#include<utility>
#include<array>
template<std::size_t O, typename T, std::size_t N, std::size_t... I>
constexpr std::array<T, sizeof...(I)>
f(const std::array<T, N> &arr, std::index_sequence<I...>) {
return { std::get<I+O>(arr)... };
}
template<std::size_t B, std::size_t E, typename T, std::size_t N>
constexpr auto f(const std::array<T, N> &arr) {
return f<B>(arr, std::make_index_sequence<E-B>());
}
int main() {
constexpr std::array<int, 3> a1 = { 0, 1, 2 };
constexpr auto a2 = f<1, 2>(a1);
static_assert(a1[1] == a2[0], "!");
}
In this case, a2 is equal to { 1 }.
It's worth it checking B and E so as to verify that E is greater than B, but the example should give an idea of what's the way to do it.
To port it to C++11:
Do not use auto as return type, but explicitly specify std::array (easy)
Search on the web one of the available C++11 implementations of integer_sequence and make_index_sequence and use it
If it's fine to be explicit about the indexes and not use a range, here is a naïve snippet that should work in C++11:
#include<cstddef>
#include<utility>
#include<array>
template<std::size_t... I, typename T, std::size_t N>
constexpr std::array<T, sizeof...(I)>
f(const std::array<T, N> &arr) {
return { std::get<I>(arr)... };
}
int main() {
constexpr std::array<int, 3> a1 = { 0, 1, 2 };
constexpr auto a2 = f<1>(a1);
static_assert(a1[1] == a2[0], "!");
}
As in the previous example, a2 is { 1 }.
I like the skypjack's solution but it doesn't extract the requested values. skypjack's version has two parameters, "begin" and "end". The OP requested "stride" or "frequency" and "begin".
I've modified it to match the OP's requested "frequency" and "start" arguments, giving the template non-type parameters more self-explaining names, and rewriting a couple of index calculations:
#include<utility>
#include<iostream>
#include<array>
template <std::size_t Freq, std::size_t Start, typename T, std::size_t Dim,
std::size_t... I>
constexpr std::array<T, sizeof...(I)>
extractHelper (const std::array<T, Dim> & arr,
std::integer_sequence<std::size_t, I...>)
{ return { { std::get<Freq*I+Start>(arr)... } }; }
template <std::size_t Freq, std::size_t Start, typename T, std::size_t Dim>
constexpr auto extractSamples (const std::array<T, Dim> & arr)
{ return extractHelper<Freq, Start>
(arr, std::make_index_sequence<(Dim+Freq-1-Start)/Freq>()); }
Here is some test code:
int main()
{
constexpr std::array<int, 8> a1 = { { 0, 1, 2, 3, 4, 5, 6, 7 } };
constexpr auto e1 = extractSamples<2, 0>(a1);
constexpr auto e2 = extractSamples<2, 1>(a1);
constexpr auto e3 = extractSamples<3, 0>(a1);
constexpr auto e4 = extractSamples<3, 1>(a1);
constexpr auto e5 = extractSamples<3, 2>(a1);
std::cout << "samples<2, 0>: ";
for ( auto const & i : e1 )
std::cout << ' ' << i;
std::cout << "\nsamples<2, 1>: ";
for ( auto const & i : e2 )
std::cout << ' ' << i;
std::cout << "\nsamples<3, 0>: ";
for ( auto const & i : e3 )
std::cout << ' ' << i;
std::cout << "\nsamples<3, 1>: ";
for ( auto const & i : e4 )
std::cout << ' ' << i;
std::cout << "\nsamples<3, 2>: ";
for ( auto const & i : e5 )
std::cout << ' ' << i;
std::cout << std::endl;
return 0;
}
The output is:
samples<2, 0>: 0 2 4 6
samples<2, 1>: 1 3 5 7
samples<3, 0>: 0 3 6
samples<3, 1>: 1 4 7
samples<3, 2>: 2 5
which matches the OP's requests
Here's a solution in C++11 without additives. As usual,
compiletime recursion makes do for the lack of C++14's std::index_sequence
- in this case by recursively assembling the list of indices that
select the desired sample of the data array.
Given some:
constexpr std::array<T,N> data{{...}};
initialized ... with the Ts of your choice, then:
constexpr auto sample = get_sample<Stride,Offset>(data);
will define sample as a compiletime
std::array<T,M>
populated with the M elements of data obtained by selecting the element
at offset Offset from the start of successive Stride-sized intervals of
data.
#include <array>
#include <type_traits>
constexpr std::size_t
sample_size(std::size_t size, std::size_t stride, std::size_t off)
{
return stride == 0 ? 0 : ((size - off) / stride) +
(off + (((size - off) / stride) * stride) < size);
}
template<
std::size_t Stride = 1, std::size_t Off = 0,
typename T, std::size_t Size, std::size_t ...Is
>
constexpr typename std::enable_if<
sizeof ...(Is) == sample_size(Size,Stride,Off),
std::array<T, sample_size(Size,Stride,Off)>
>::type
get_sample(std::array<T,Size> const & data)
{
return std::array<T,sample_size(Size,Stride,Off)>{{data[Is]... }};
}
template<
std::size_t Stride = 1, std::size_t Off = 0,
typename T, std::size_t Size, std::size_t ...Is
>
constexpr typename std::enable_if<
sizeof ...(Is) != sample_size(Size,Stride,Off),
std::array<T, sample_size(Size,Stride,Off)>
>::type
get_sample(std::array<T,Size> const & data)
{
return
get_sample<Stride,Off,T,Size,Is...,(sizeof...(Is) * Stride) + Off>
(data);
}
By default Stride is 1 and Off is 0. The helper function sample_size
embeds the convention that if Stride is 0 you get an empty sample.
For an illustrative program, you can append:
constexpr std::array<int,5> data1{{0,1,2,3,4}};
constexpr auto sample1 = get_sample(data1);
constexpr auto sample2 = get_sample<2>(data1);
constexpr auto sample3 = get_sample<2,1>(data1);
constexpr auto sample4 = get_sample<6>(data1);
constexpr auto sample5 = get_sample<6,5>(data1);
static_assert(sample5.size() == 0,"");
constexpr std::array<float,6> data2{{1.1,2.2,3.3,4.4,5.5,6.6}};
constexpr auto sample6 = get_sample<2>(data2);
constexpr auto sample7 = get_sample<2,3>(data2);
constexpr auto sample8 = get_sample<3,2>(data2);
constexpr std::array<int,0> data3{};
constexpr auto sample9 = get_sample<0>(data3);
static_assert(sample9.size() == 0,"");
constexpr auto sample10 = get_sample<2>(data3);
static_assert(sample10.size() == 0,"");
#include <iostream>
int main()
{
std::cout << "get_sample<> of {0,1,2,3,4}\n";
for (auto const & e : sample1) {
std::cout << e << ' ';
}
std::cout << '\n';
std::cout << "get_sample<2> of {0,1,2,3,4}\n";
for (auto const & e : sample2) {
std::cout << e << ' ';
}
std::cout << '\n';
std::cout << "get_sample<2,1> of {0,1,2,3,4}\n";
for (auto const & e : sample3) {
std::cout << e << ' ';
}
std::cout << '\n';
std::cout << "get_sample<6> of {0,1,2,3,4}\n";
for (auto const & e : sample4) {
std::cout << e << ' ';
}
std::cout << '\n';
std::cout << "get_sample<2> of {{1.1,2.2,3.3,4.4,5.5,6.6}}\n";
for (auto const & e : sample6) {
std::cout << e << ' ';
}
std::cout << '\n';
std::cout << "get_sample<2,3> of {{1.1,2.2,3.3,4.4,5.5,6.6}}\n";
for (auto const & e : sample7) {
std::cout << e << ' ';
}
std::cout << '\n';
std::cout << "get_sample<3,2> of {{1.1,2.2,3.3,4.4,5.5,6.6}}\n";
for (auto const & e : sample8) {
std::cout << e << ' ';
}
std::cout << '\n';
return 0;
}
which reports:
get_sample<> of {0,1,2,3,4}
0 1 2 3 4
get_sample<2> of {0,1,2,3,4}
0 2 4
get_sample<2,1> of {0,1,2,3,4}
1 3
get_sample<6> of {0,1,2,3,4}
0
get_sample<2> of {1.1,2.2,3.3,4.4,5.5,6.6}
1.1 3.3 5.5
get_sample<2,3> of {1.1,2.2,3.3,4.4,5.5,6.6}
4.4 6.6
get_sample<3,2> of {1.1,2.2,3.3,4.4,5.5,6.6}
3.3 6.6
See it live
If you want to apply this to your class Def, you would redefine it in an amenable
way like:
struct Def {
static constexpr int N = 5;
static constexpr std::array<double,N> data{{0,1,2,3,4}};
};
and get your compiletime sample like:
constexpr auto s = get_sample<2,1>(Def::data);
(g++ 6.1/clang++ 3.8, -std=c++11 -Wall -Wextra -pedantic)
Is there an easy way to get a slice of an array in C++?
I.e., I've got
array<double, 10> arr10;
and want to get array consisting of five first elements of arr10:
array<double, 5> arr5 = arr10.???
(other than populating it by iterating through first array)
The constructors for std::array are implicitly defined so you can't initialize it with a another container or a range from iterators. The closest you can get is to create a helper function that takes care of the copying during construction. This allows for single phase initialization which is what I believe you're trying to achieve.
template<class X, class Y>
X CopyArray(const Y& src, const size_t size)
{
X dst;
std::copy(src.begin(), src.begin() + size, dst.begin());
return dst;
}
std::array<int, 5> arr5 = CopyArray<decltype(arr5)>(arr10, 5);
You can also use something like std::copy or iterate through the copy yourself.
std::copy(arr10.begin(), arr10.begin() + 5, arr5.begin());
Sure. Wrote this:
template<int...> struct seq {};
template<typename seq> struct seq_len;
template<int s0,int...s>
struct seq_len<seq<s0,s...>>:
std::integral_constant<std::size_t,seq_len<seq<s...>>::value> {};
template<>
struct seq_len<seq<>>:std::integral_constant<std::size_t,0> {};
template<int Min, int Max, int... s>
struct make_seq: make_seq<Min, Max-1, Max-1, s...> {};
template<int Min, int... s>
struct make_seq<Min, Min, s...> {
typedef seq<s...> type;
};
template<int Max, int Min=0>
using MakeSeq = typename make_seq<Min,Max>::type;
template<std::size_t src, typename T, int... indexes>
std::array<T, sizeof...(indexes)> get_elements( seq<indexes...>, std::array<T, src > const& inp ) {
return { inp[indexes]... };
}
template<int len, typename T, std::size_t src>
auto first_elements( std::array<T, src > const& inp )
-> decltype( get_elements( MakeSeq<len>{}, inp ) )
{
return get_elements( MakeSeq<len>{}, inp );
}
Where the compile time indexes... does the remapping, and MakeSeq makes a seq from 0 to n-1.
Live example.
This supports both an arbitrary set of indexes (via get_elements) and the first n (via first_elements).
Use:
std::array< int, 10 > arr = {0,1,2,3,4,5,6,7,8,9};
std::array< int, 6 > slice = get_elements(arr, seq<2,0,7,3,1,0>() );
std::array< int, 5 > start = first_elements<5>(arr);
which avoids all loops, either explicit or implicit.
2018 update, if all you need is first_elements:
Less boilerplaty solution using C++14 (building up on Yakk's pre-14 answer and stealing from "unpacking" a tuple to call a matching function pointer)
template < std::size_t src, typename T, int... I >
std::array< T, sizeof...(I) > get_elements(std::index_sequence< I... >, std::array< T, src > const& inp)
{
return { inp[I]... };
}
template < int N, typename T, std::size_t src >
auto first_elements(std::array<T, src > const& inp)
-> decltype(get_elements(std::make_index_sequence<N>{}, inp))
{
return get_elements(std::make_index_sequence<N>{}, inp);
}
Still cannot explain why this works, but it does (for me on Visual Studio 2017).
This answer might be late... but I was just toying around with slices - so here is my little home brew of std::array slices.
Of course, this comes with a few restrictions and is not ultimately general:
The source array from which a slice is taken must not go out of scope. We store a reference to the source.
I was looking for constant array slices first and did not try to expand this code to both const and non const slices.
But one nice feature of the code below is, that you can take slices of slices...
// ParCompDevConsole.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include "pch.h"
#include <cstdint>
#include <iostream>
#include <array>
#include <stdexcept>
#include <sstream>
#include <functional>
template <class A>
class ArraySliceC
{
public:
using Array_t = A;
using value_type = typename A::value_type;
using const_iterator = typename A::const_iterator;
ArraySliceC(const Array_t & source, size_t ifirst, size_t length)
: m_ifirst{ ifirst }
, m_length{ length }
, m_source{ source }
{
if (source.size() < (ifirst + length))
{
std::ostringstream os;
os << "ArraySliceC::ArraySliceC(<source>,"
<< ifirst << "," << length
<< "): out of bounds. (ifirst + length >= <source>.size())";
throw std::invalid_argument( os.str() );
}
}
size_t size() const
{
return m_length;
}
const value_type& at( size_t index ) const
{
return m_source.at( m_ifirst + index );
}
const value_type& operator[]( size_t index ) const
{
return m_source[m_ifirst + index];
}
const_iterator cbegin() const
{
return m_source.cbegin() + m_ifirst;
}
const_iterator cend() const
{
return m_source.cbegin() + m_ifirst + m_length;
}
private:
size_t m_ifirst;
size_t m_length;
const Array_t& m_source;
};
template <class T, size_t SZ>
std::ostream& operator<<( std::ostream& os, const std::array<T,SZ>& arr )
{
if (arr.size() == 0)
{
os << "[||]";
}
else
{
os << "[| " << arr.at( 0 );
for (auto it = arr.cbegin() + 1; it != arr.cend(); it++)
{
os << "," << (*it);
}
os << " |]";
}
return os;
}
template<class A>
std::ostream& operator<<( std::ostream& os, const ArraySliceC<A> & slice )
{
if (slice.size() == 0)
{
os << "^[||]";
}
else
{
os << "^[| " << slice.at( 0 );
for (auto it = slice.cbegin() + 1; it != slice.cend(); it++)
{
os << "," << (*it);
}
os << " |]";
}
return os;
}
template<class A>
A unfoldArray( std::function< typename A::value_type( size_t )> producer )
{
A result;
for (size_t i = 0; i < result.size(); i++)
{
result[i] = producer( i );
}
return result;
}
int main()
{
using A = std::array<float, 10>;
auto idf = []( size_t i ) -> float { return static_cast<float>(i); };
const auto values = unfoldArray<A>(idf);
std::cout << "values = " << values << std::endl;
// zero copy slice of values array.
auto sl0 = ArraySliceC( values, 2, 4 );
std::cout << "sl0 = " << sl0 << std::endl;
// zero copy slice of the sl0 (the slice of values array)
auto sl01 = ArraySliceC( sl0, 1, 2 );
std::cout << "sl01 = " << sl01 << std::endl;
return 0;
}
Background
Consider the following:
template <unsigned N>
struct Fibonacci
{
enum
{
value = Fibonacci<N-1>::value + Fibonacci<N-2>::value
};
};
template <>
struct Fibonacci<1>
{
enum
{
value = 1
};
};
template <>
struct Fibonacci<0>
{
enum
{
value = 0
};
};
This is a common example and we can get the value of a Fibonacci number as a compile-time constant:
int main(void)
{
std::cout << "Fibonacci(15) = ";
std::cout << Fibonacci<15>::value;
std::cout << std::endl;
}
But you obviously cannot get the value at runtime:
int main(void)
{
std::srand(static_cast<unsigned>(std::time(0)));
// ensure the table exists up to a certain size
// (even though the rest of the code won't work)
static const unsigned fibbMax = 20;
Fibonacci<fibbMax>::value;
// get index into sequence
unsigned fibb = std::rand() % fibbMax;
std::cout << "Fibonacci(" << fibb << ") = ";
std::cout << Fibonacci<fibb>::value;
std::cout << std::endl;
}
Because fibb is not a compile-time constant.
Question
So my question is:
What is the best way to peek into this table at run-time? The most obvious solution (and "solution" should be taken lightly), is to have a large switch statement:
unsigned fibonacci(unsigned index)
{
switch (index)
{
case 0:
return Fibonacci<0>::value;
case 1:
return Fibonacci<1>::value;
case 2:
return Fibonacci<2>::value;
.
.
.
case 20:
return Fibonacci<20>::value;
default:
return fibonacci(index - 1) + fibonacci(index - 2);
}
}
int main(void)
{
std::srand(static_cast<unsigned>(std::time(0)));
static const unsigned fibbMax = 20;
// get index into sequence
unsigned fibb = std::rand() % fibbMax;
std::cout << "Fibonacci(" << fibb << ") = ";
std::cout << fibonacci(fibb);
std::cout << std::endl;
}
But now the size of the table is very hard coded and it wouldn't be easy to expand it to say, 40.
The only one I came up with that has a similiar method of query is this:
template <int TableSize = 40>
class FibonacciTable
{
public:
enum
{
max = TableSize
};
static unsigned get(unsigned index)
{
if (index == TableSize)
{
return Fibonacci<TableSize>::value;
}
else
{
// too far, pass downwards
return FibonacciTable<TableSize - 1>::get(index);
}
}
};
template <>
class FibonacciTable<0>
{
public:
enum
{
max = 0
};
static unsigned get(unsigned)
{
// doesn't matter, no where else to go.
// must be 0, or the original value was
// not in table
return 0;
}
};
int main(void)
{
std::srand(static_cast<unsigned>(std::time(0)));
// get index into sequence
unsigned fibb = std::rand() % FibonacciTable<>::max;
std::cout << "Fibonacci(" << fibb << ") = ";
std::cout << FibonacciTable<>::get(fibb);
std::cout << std::endl;
}
Which seems to work great. The only two problems I see are:
Potentially large call stack, since calculating Fibonacci<2> requires we go through TableMax all the way to 2, and:
If the value is outside of the table, it returns zero as opposed to calculating it.
So is there something I am missing? It seems there should be a better way to pick out these values at runtime.
A template metaprogramming version of a switch statement perhaps, that generates a switch statement up to a certain number?
Thanks in advance.
template <unsigned long N>
struct Fibonacci
{
enum
{
value = Fibonacci<N-1>::value + Fibonacci<N-2>::value
};
static void add_values(vector<unsigned long>& v)
{
Fibonacci<N-1>::add_values(v);
v.push_back(value);
}
};
template <>
struct Fibonacci<0>
{
enum
{
value = 0
};
static void add_values(vector<unsigned long>& v)
{
v.push_back(value);
}
};
template <>
struct Fibonacci<1>
{
enum
{
value = 1
};
static void add_values(vector<unsigned long>& v)
{
Fibonacci<0>::add_values(v);
v.push_back(value);
}
};
int main()
{
vector<unsigned long> fibonacci_seq;
Fibonacci<45>::add_values(fibonacci_seq);
for (int i = 0; i <= 45; ++i)
cout << "F" << i << " is " << fibonacci_seq[i] << '\n';
}
After much thought into the problem, I came up with this solution. Of course, you still have to add the values to a container at run-time, but (importantly) they are not computed at run-time.
As a side note, it's important not to define Fibonacci<1> above Fibonacci<0>, or your compiler will get very confused when it resolves the call to Fibonacci<0>::add_values, since Fibonacci<0>'s template specialization has not been specified.
Of course, TMP has its limitations: You need a precomputed maximum, and getting the values at run-time requires recursion (since templates are defined recursively).
I know this question is old, but it intrigued me and I had to have a go at doing without a dynamic container filled at runtime:
#ifndef _FIBONACCI_HPP
#define _FIBONACCI_HPP
template <unsigned long N>
struct Fibonacci
{
static const unsigned long long value = Fibonacci<N-1>::value + Fibonacci<N-2>::value;
static unsigned long long get_value(unsigned long n)
{
switch (n) {
case N:
return value;
default:
return n < N ? Fibonacci<N-1>::get_value(n)
: get_value(n-2) + get_value(n-1);
}
}
};
template <>
struct Fibonacci<0>
{
static const unsigned long long value = 0;
static unsigned long long get_value(unsigned long n)
{
return value;
}
};
template <>
struct Fibonacci<1>
{
static const unsigned long long value = 1;
static unsigned long get_value(unsigned long n)
{
if(n == N){
return value;
}else{
return 0; // For `Fibonacci<N>::get(0);`
}
}
};
#endif
This seems to work, and when compiled with optimizations (not sure if you were going to allow that), the call stack does not get to deep - there is normal runtime recursion on the stack of course for values (arguments) n > N, where N is the TableSize used in the template instantiation. However, once you go below the TableSize the generated code substitutes a constant computed at compile time, or at worst a value "computed" by dropping through a jump table (compiled in gcc with -c -g -Wa,-adhlns=main.s and checked the listing), the same as I reckon your explicit switch statement would result in.
When used like this:
int main()
{
std::cout << "F" << 39 << " is " << Fibonacci<40>::get_value(39) << '\n';
std::cout << "F" << 45 << " is " << Fibonacci<40>::get_value(45) << '\n';
}
There is no call to a computation at all in the first case (value computed at compile time), and in the second case the call stack depth is at worst:
fibtest.exe!Fibonacci<40>::get_value(unsigned long n=41) Line 18 + 0xe bytes C++
fibtest.exe!Fibonacci<40>::get_value(unsigned long n=42) Line 18 + 0x2c bytes C++
fibtest.exe!Fibonacci<40>::get_value(unsigned long n=43) Line 18 + 0x2c bytes C++
fibtest.exe!Fibonacci<40>::get_value(unsigned long n=45) Line 18 + 0xe bytes C++
fibtest.exe!main() Line 9 + 0x7 bytes C++
fibtest.exe!__tmainCRTStartup() Line 597 + 0x17 bytes C
I.e. it recurses until it finds a value in the "Table". (verified by stepping through Disassembly in the debugger line by line, also by replacing the test ints by a random number <= 45)
The recursive part could also be replaced by the linear iterative solution:
static unsigned long long get_value(unsigned long n)
{
switch (n) {
case N:
return value;
default:
if (n < N) {
return Fibonacci<N-1>::get_value(n);
} else {
// n > N
unsigned long long i = Fibonacci<N-1>::value, j = value, t;
for (unsigned long k = N; k < n; k++) {
t = i + j;
i = j;
j = t;
}
return j;
}
}
}
If you have C++ compiler which supports variadic templates (C++0x standard ) you can save fibonacii sequence in a tuple at the compile time. At runtime you can access any element from that tuple by indexing.
#include <tuple>
#include <iostream>
template<int N>
struct Fib
{
enum { value = Fib<N-1>::value + Fib<N-2>::value };
};
template<>
struct Fib<1>
{
enum { value = 1 };
};
template<>
struct Fib<0>
{
enum { value = 0 };
};
// ----------------------
template<int N, typename Tuple, typename ... Types>
struct make_fibtuple_impl;
template<int N, typename ... Types>
struct make_fibtuple_impl<N, std::tuple<Types...> >
{
typedef typename make_fibtuple_impl<N-1, std::tuple<Fib<N>, Types... > >::type type;
};
template<typename ... Types>
struct make_fibtuple_impl<0, std::tuple<Types...> >
{
typedef std::tuple<Fib<0>, Types... > type;
};
template<int N>
struct make_fibtuple : make_fibtuple_impl<N, std::tuple<> >
{};
int main()
{
auto tup = typename make_fibtuple<25>::type();
std::cout << std::get<20>(tup).value;
std::cout << std::endl;
return 0;
}
With C++11: you may create a std::array and a simple getter: https://ideone.com/F0b4D3
namespace detail
{
template <std::size_t N>
struct Fibo :
std::integral_constant<size_t, Fibo<N - 1>::value + Fibo<N - 2>::value>
{
static_assert(Fibo<N - 1>::value + Fibo<N - 2>::value >= Fibo<N - 1>::value,
"overflow");
};
template <> struct Fibo<0u> : std::integral_constant<size_t, 0u> {};
template <> struct Fibo<1u> : std::integral_constant<size_t, 1u> {};
template <std::size_t ... Is>
constexpr std::size_t fibo(std::size_t n, index_sequence<Is...>)
{
return const_cast<const std::array<std::size_t, sizeof...(Is)>&&>(
std::array<std::size_t, sizeof...(Is)>{{Fibo<Is>::value...}})[n];
}
template <std::size_t N>
constexpr std::size_t fibo(std::size_t n)
{
return n < N ?
fibo(n, make_index_sequence<N>()) :
throw std::runtime_error("out of bound");
}
} // namespace detail
constexpr std::size_t fibo(std::size_t n)
{
// 48u is the highest
return detail::fibo<48u>(n);
}
In C++14, you can simplify some function:
template <std::size_t ... Is>
constexpr std::size_t fibo(std::size_t n, index_sequence<Is...>)
{
constexpr std::array<std::size_t, sizeof...(Is)> fibos{{Fibo<Is>::value...}};
return fibos[n];
}
My idea is to recursively save the fibonacci sequence in the variadic templates then convert it into an array. All of this are done at compile-time.
For example with n = 5 we have:
F<5>::array
= F<4, 0>::array
= F<3, 0, 1>::array
= F<2, 0, 1, 1>::array
= F<1, 0, 1, 1, 2>::array
= F<0, 0, 1, 1, 2, 3>::array
= { 0, 1, 1, 2, 3 }
Then we can index the array at runtime.
My C++14 implementation:
#include <cstdint>
#include <array>
#include <iostream>
template<uint64_t n>
struct Helper { static constexpr uint64_t value = Helper<n - 1>::value + Helper<n - 2>::value; };
template<>
struct Helper<0> { static constexpr uint64_t value = 0; };
template<>
struct Helper<1> { static constexpr uint64_t value = 1; };
template<u_int64_t x>
class Fib {
private:
template<u_int64_t n, u_int64_t...rest>
struct Get {
static constexpr std::array<u_int64_t, n + sizeof...(rest)> value = Get<n - 1, rest..., Helper<sizeof...(rest)>::value>::value;
};
template<u_int64_t...rest>
struct Get<0, rest...> {
static constexpr std::array<u_int64_t, sizeof...(rest)> value{rest...};
};
public:
static constexpr std::array<u_int64_t, x> sequence = Get<x>::value;
};
template<u_int64_t x>
constexpr std::array<u_int64_t, x> Fib<x>::sequence;
int main() {
for (int i = 0; i < 45; i++) std::cout << "F" << i << " = " << Fib<45>::sequence[i] << std::endl;
}
One of the basic tennants of C (and for the most part C++) is that you don't pay for what you don't need.
The automatic generation of look-up tables is just not something that the compiler needs to do for you. Even if you need that functionality, not everyone else necessarly does.
If you want a lookup table, write a program to make one. Then use that data in your program.
Don't use a template metaprogram if you want values to be calculated at runtime, just use a regular program to calculate values.
You can generate the switch or a static array using preprocessor metaprogramming techniques.
It is a good decision if the complexity does not exceed the limitations of that approach, and you prefer not extending your toolchain with extra steps that generate code or data.