How to define C++ struct for configuration? - c++

I have been trying to solve following problem in C++. I would like to define a struct containing a configuration parameters for some software module. The configuration parameters are basically a floating point values and they are of two types:
parameters which are independent i.e. their values are given directly by some floating point numbers
parameters which are dependent i.e. their values are given by some expressions where the operands are the independent parameters
Here is an example
struct Configuration {
float param_independent_01;
float param_independent_02;
float param_dependent_01; // param_independent_01 + param_independent_02
float param_dependent_02; // 1.5f*param_independent_01/(param_independent_01 + param_independent_02)
};
I have been looking for a solution which enables the client code to only set values for the independent parameters and the dependent parameters values will be calculated automatically behind the scene.
Configuration config = {
param_independent_01 = 0.236f,
param_independent_02 = 0.728f
// param_dependent_01 = 0.236f + 0.728f
// param_dependent_02 = 1.5f*0.236f/(0.236f + 0.728f)
};
I suppose that the Configuration structure will be instantiated only once and the values of the parameters are known at compile time. Can anybody give me an advice how to do that in the C++?

One approach to achieve this behavior is to make use of C++'s constructor initialization list.
struct Configuration {
float param_independent_01;
float param_independent_02;
float param_dependent_01;
float param_dependent_02;
Configuration(float p1, float p2) :
param_independent_01(p1),
param_independent_02(p2),
param_dependent_01(p1 + p2),
param_dependent_02(1.5f * p1 / (p1 + p2)
)
{}
};
int main() {
Configuration config(0.236f, 0.728f);
return 0;
}

Or just inline constexpr variables in a namespace (can be put in a header).
This allows you to write some constexpr (consteval) functions to calculate the values too. (Not everything needs to be a class or a struct)
// header file
#pragma once
namespace configuration
{
inline constexpr float get_param_dependent_02(const float p1, const float p2)
{
return (1.5f * p1) / (p1+p2);
}
inline constexpr float param_independent_01{ 0.236f };
inline constexpr float param_independent_02{ 0.728f };
inline constexpr float param_dependent_01 = param_independent_01 + param_independent_02; // direct
inline constexpr float param_dependent_02 = get_param_dependent_02(param_independent_01, param_independent_02); // or through constexpr/consteval function
};
int main()
{
float f = configuration::param_dependent_02;
}

If you know the configuration is not going to change at runtime, you can implement a constexpr constructor for Configuration, and then define a constexpr Configuration variable. The construction will be done at compile time (see the generated assembler code for the godbolt link below).
If you wanted to make sure the configuration is not going to change at runtime, I would change Configuration into a class with private members, and just provide accessors for those members.
Notice also that the constructor may throw (due to a division by zero). If you want to take control of that situation, you may want to try-catch the setting of the dependent parameter 2 in the constructor's body.
[Demo]
#include <fmt/format.h>
#include <iostream>
class Configuration {
float param_independent_01;
float param_independent_02;
float param_dependent_01;
float param_dependent_02;
public:
constexpr Configuration(float p1, float p2)
: param_independent_01{p1}
, param_independent_02{p2}
, param_dependent_01{p1 + p2}
, param_dependent_02{(p1 * 1.5f)/param_dependent_01}
{}
auto get_pi1() { return param_independent_01; }
auto get_pi2() { return param_independent_02; }
auto get_pd1() { return param_dependent_01; }
auto get_pd2() { return param_dependent_02; }
friend std::ostream& operator<<(std::ostream& os, const Configuration& c) {
return os << fmt::format("pi1: {}\npi2: {}\npd1: {}\npd2: {}\n",
c.param_independent_01, c.param_independent_02,
c.param_dependent_01, c.param_dependent_02);
}
};
int main() {
constexpr Configuration c{3.14, 9.8};
std::cout << c;
}

No need for a class with a custom constructor, just do this:
struct Configuration
{
float param_independent_01 = 0; // Always initialize all class members.
float param_independent_02 = 0;
float param_dependent_01() const {return param_independent_01 + param_independent_02;}
float param_dependent_02() const {return 1.5f*param_independent_01/(param_independent_01 + param_independent_02);}
};

Related

templating a primitive in C++

I have some code with fairly complicated logic that passing around angles in both radians and degrees. All of the variables are doubles. It would be helpful to add some additional guards to prevent passing a radians to a function that requires the value in degrees. The code below uses a struct and does work but requires .value to get the actual double back. Is it possible to template a primitive without using a struct? Is there a better way of doing this? I'm currently working C++17.
enum class AngleType
{
Degree,
Radian
};
template <AngleType T>
struct Angle
{
double value;
};
void example_function(Angle<AngleType::Radian> angle_radians) { };
A somewhat common way to do this is provide a conversion operator. Example:
#include <iostream>
#include <math.h>
template<int N, typename T>
struct AngleType
{
T value;
AngleType(T val) : value(val) {}
operator T() const noexcept
{
return value;
}
};
using AngleRadians = AngleType<0, double>;
using AngleDegrees = AngleType<1, double>;
void example_func(AngleRadians angle) {
std::cout << "angle in radians = " << angle << "\n";
}
int main(int argc, char **argv)
{
AngleRadians rad = M_PI;
AngleDegrees deg = 180;
example_func(rad);
example_func(deg); // <-- compiler error
}
It has its drawbacks, but it may be good enough for what you're trying to do.
Depends on what you really need, you could actually get rid of Angle and AngleType all together with User-defined literals.
Before starting, you need to decide the base unit you want to use. For my example, I will use radian as base unit.
The idea here is every time you attempt to use a number in degree, it would automatically convert that into radian.
// User-defined literal
constexpr auto operator"" _deg (long double deg)
{
return deg * PI / 180;
}
constexpr auto operator"" _deg (unsigned long long int deg)
{
return 1.0_deg * deg;
}
After defining this two, if you want to write a number in degree, you can simply use:
auto a = 90.0_deg;
And it would be equivalent to:
long double a = ((long double)90.0 * PI / 180);
To make it more consistent, you can also define a literal for _rad, and just use:
constexpr auto operator"" _rad (long double rad)
{
return rad;
}
constexpr auto operator"" _rad (unsigned long long int rad)
{
return 1.0_rad * rad;
}
Now every time you assign a number to something, you would do:
auto a = 3.14_rad, b = 180_deg;
However, do note that you cannot use literals on variables, so you can't do things like PI_rad. But, since we already settled the base unit as radian, then all variables are stored in radian anyways.
Also note that the parameter for those function are set to long double and unsigned long long int, as they were required by standard.

Subtle differences in output values (+/-) between float and doubles

This is a follow up from an older question found here: Chaining Function Calls and user Mooing Duck provided me with an answer that works through the use of Proxy Class and Proxy functions. I have managed to template this class and it appears to be working. I'm getting completely different results between float and double...
Here are the non templated versions of the classes and application for floats and doubles:
Just replace all floats with doubles within the classes, functions, and proxy functions... The main program won't change except for the arguments.
#include <cmath>
#include <exception>
#include <iostream>
#include <utility>
namespace pipes {
const double PI = 4 * atan(1);
struct vec2 {
float x;
float y;
};
std::ostream& operator<<(std::ostream& out, vec2 v2) {
return out << v2.x << ',' << v2.y;
}
vec2 translate(vec2 in, float a) {
return vec2{ in.x + a, in.y + a };
}
vec2 rotate(vec2 in, float a) {
// convert a in degrees to radians:
a *= (float)(PI / 180.0);
return vec2{ in.x*cos(a) - in.y*sin(a),
in.x*sin(a) + in.y*cos(a) };
}
vec2 scale(vec2 in, float a) {
return vec2{ in.x*a, in.y*a };
}
// proxy class
template<class rhst, vec2(*f)(vec2, rhst)>
class vec2_op1 {
std::decay_t<rhst> rhs; // store the parameter until the call
public:
vec2_op1(rhst rhs_) : rhs(std::forward<rhst>(rhs_)) {}
vec2 operator()(vec2 lhs) { return f(lhs, std::forward<rhst>(rhs)); }
};
// proxy methods
vec2_op1<float, translate> translate(float a) { return { a }; }
vec2_op1<float, rotate> rotate(float a) { return { a }; }
vec2_op1<float, scale> scale(float a) { return { a }; }
// lhs is the object, rhs is the operation on the object
template<class rhst, vec2(*f)(vec2, rhst)>
vec2& operator|(vec2& lhs, vec2_op1<rhst, f>&& op) { return lhs = op(lhs); }
} // namespace pipes
int main() {
try {
pipes::vec2 a{ 1.0, 0.0 };
pipes::vec2 b = (a | pipes::rotate(90.0));
std::cout << b << '\n';
} catch (const std::exception& e) {
std::cerr << e.what() << "\n\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
Output for float:
-4.37114e-08,1
Output for double:
6.12323e-17,1
Here is the templated version...
#include <cmath>
#include <exception>
#include <iostream>
#include <utility>
namespace pipes {
const double PI = 4 * atan(1);
template<typename Ty>
struct vec2_t {
Ty x;
Ty y;
};
template<typename Ty>
std::ostream& operator<<(std::ostream& out, vec2_t<Ty> v2) {
return out << v2.x << ',' << v2.y;
}
template<typename Ty>
vec2_t<Ty> translate(vec2_t<Ty> in, Ty a) {
return vec2_t<Ty>{ in.x + a, in.y + a };
}
template<typename Ty>
vec2_t<Ty> rotate(vec2_t<Ty> in, Ty a) {
// convert a in degrees to radians:
a *= (Ty)(PI / 180.0);
return vec2_t<Ty>{ in.x*cos(a) - in.y*sin(a),
in.x*sin(a) + in.y*cos(a) };
}
template<typename Ty>
vec2_t<Ty> scale(vec2_t<Ty> in, Ty a) {
return vec2_t<Ty>{ in.x*a, in.y*a };
}
// proxy class
template<class rhst, typename Ty, vec2_t<Ty>(*f)(vec2_t<Ty>, rhst)>
class vec2_op1 {
std::decay_t<rhst> rhs; // store the parameter until the call
public:
vec2_op1(rhst rhs_) : rhs(std::forward<rhst>(rhs_)) {}
vec2_t<Ty> operator()(vec2_t<Ty> lhs) { return f(lhs, std::forward<rhst>(rhs)); }
};
// proxy methods
template<typename Ty>
vec2_op1<Ty, Ty, translate<Ty>> translate(Ty a) { return { a }; }
template<typename Ty>
vec2_op1<Ty, Ty, rotate<Ty>> rotate(Ty a) { return { a }; }
template<typename Ty>
vec2_op1<Ty, Ty, scale<Ty>> scale(Ty a) { return { a }; }
// overloaded | operator for chaining function calls to vec2_t objects
// lhs is the object, rhs is the operation on the object
template<class rhst, typename Ty, vec2_t<Ty>(*f)(vec2_t<Ty>, rhst)>
vec2_t<Ty>& operator|(vec2_t<Ty>& lhs, vec2_op1<rhst, Ty, f>&& op) { return lhs = op(lhs); }
} // namespace pipes
// for double just instantiate with double...
int main() {
try {
pipes::vec2_t<float> a{ 1.0f, 0.0f };
pipes::vec2_t<float> b = (a | pipes::rotate(90.0f));
std::cout << b << '\n';
} catch (const std::exception& e) {
std::cerr << e.what() << "\n\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
The output for floats:
-4.37114e-08,1
The output for doubles:
6.12323e-17,1
This goes to show that the conversion of my class to a class template appears to be working. I understand that there may be a bit of precision lost due to conversion from double to float or widening from float to double when casting, however, I can't seem to wrap my mind around why there is such a difference in output values from one to the other...
The rotation of the point or vector {1,0} at 90 degrees or PI/2 radians should be {0,1}. I understand how floating-point arithmetic works and that the generated output for the x values is relatively close to 0 so they should be considered 0 for all tense and purposes and I can include the use an epsilon checking function to test if it is close enough to 0 to set it directly to 0 which is not an issue...
What intrigues my curiosity is why is it -4.3...e-8 for float and +6.1...e-17 for double? In the float case, I'm getting negative values, and for the double case, I'm getting positive values. In both cases yes they are extremely small and close to 0 which is fine, but opposite signs, that has me scratching my head?
I'm seeking clarity to get a better insight as to why these values are being generated the way they are... Is it coming from the type-conversion or is it due to the trig function that is being used? Or a combination of both? Just trying to pinpoint where the divergence of signs is coming from...
I need to be aware of what is causing this subtle difference as it will pertain to my usage of this class and its generated outputs when precision is preferred over good enough estimations.
Edit
When working with the instantiation of these function templates, specifically for the rotate function and I started to test <int> type for my vector objects... I started to get some compiler errors... The translate and scale functions were fine, I only had an issue with the rotate function due to similar reasons loss of data, narrowing and widening conversions, etc...
I had to change my rotate function's implemenation to this:
template<typename Ty>
vec2_t<Ty> rotate(vec2_t<Ty> in, Ty a) {
// convert a in degrees to radians:
auto angle = (double)(a * (PI / 180.0));
return vec2_t<Ty>{ static_cast<Ty>( in.x*cos(angle) - in.y*sin(angle) ),
static_cast<Ty>( in.x*sin(angle) + in.y*cos(angle) )
};
}
Here I'm forcing the angle to always be a double regardless of the type Ty. The rotate function still expects the same type for its argument as the type of the vec2_t object that is being instantiated. The issue was with the initialization of the vec2_t object that was being created and returned from the calculations. I had to explicitly static_cast the x and y coordinates to Ty. Now when I try the same program above for vec2_t<int> passing in a rotation value of 90 I am getting exactly 0,1 for my output.
Another interesting fact by forcing the angle to always be double and always casting the calculated values back to Ty, when I instantiate my vec2_t as either a double or float I'm always getting the positive 6.123...e-17 result back for both cases... This should also allow me to simplify the design of the is_zero() function to test if these values are close enough to 0 to set them explicitly to 0.
TL;DR: Small numbers are close to zero whatever their sign. The numbers you got are "almost zero" given the circumstances.
I'd call this "sign obsession". Two very small numbers are similar even if their signs differ. Here you're looking at numbers at the edge of accuracy of the computations you performed. They are both equally "small", given their types. Other answer(s) give hints about where exactly is the clbuttic mistake :)
Your problem is in the line:
a *= (Ty)(PI / 180.0);
For the float case, this evaluates to 1.570796371
For the double case, this evaluates to 1.570796327

VexCL vector of structs?

So I know that it is possible to use custom types with OpenCL. But I haven't been able to use them with VexCL. Creating a device vector of structs works fine, but I can't perform any operations.
As I haven't found any examples using custom types with VexCL my question is is that even possible? Thanks in advance.
VexCL does not support operations with vectors of structs out of the box. You will need to help it a bit. First, you need to tell VexCL how to spell the type name of the struct. Let's say you have the following struct defined on the host side:
struct point2d {
double x;
double y;
};
You need to provide a specification of the vex::type_name_impl struct that will generate a string corresponding to the type name of the struct. Remember that the code you are generating is C99:
namespace vex {
template <> struct type_name_impl<point2d> {
static std::string get() { return "struct point2d"; }
};
}
You will also need to make sure every generated kernel knows about your struct. This may be achieved with vex::push_program_header() function after the VexCL context has been initialized:
vex::push_program_header(ctx, "struct point2d { double x; double y; };");
This will allow you to declare vectors of the struct, and to pass the vectors to custom functions. That should be general enough. Here is the complete example:
#include <vexcl/vexcl.hpp>
// Host-side definition of the struct.
struct point2d {
double x, y;
};
// We need this for code generation.
namespace vex {
template <>
struct type_name_impl<point2d> {
static std::string get() { return "struct point2d"; }
};
}
int main() {
const size_t n = 16;
vex::Context ctx(vex::Filter::Env);
std::cout << ctx << std::endl;
// After this, every kernel will have the struct declaration in header:
vex::push_program_header(ctx, "struct point2d { double x; double y; };");
// Now we may define vectors of the struct:
vex::vector<point2d> x(ctx, n);
vex::vector<double> y(ctx, n);
// We won't be able to use the vectors in any expressions except for
// custom functions, but that should be enough:
VEX_FUNCTION(point2d, init, (double, x)(double, y),
struct point2d p = {x, y}; return p;
);
VEX_FUNCTION(double, dist, (point2d, p),
return sqrt(p.x * p.x + p.y * p.y);
);
x = init(3,4);
y = dist(x);
std::cout << y << std::endl;
}
And here is the kernel that will be generated for the assignment operation of y = dist(x);:
struct point2d { double x; double y; };
double dist
(
struct point2d p
)
{
return sqrt(p.x * p.x + p.y * p.y);
}
kernel void vexcl_vector_kernel
(
ulong n,
global double * prm_1,
global struct point2d * prm_2
)
{
for(ulong idx = get_global_id(0); idx < n; idx += get_global_size(0))
{
prm_1[idx] = dist( prm_2[idx] );
}
}

Multiple names for the same variable in C++

Is it possible in C++ to refer to the same variable using different names without using the preprocessor?
To achieve the same effect as this pseudocode
struct vec3f {
float[3] values;
};
struct color : public vec3f {
#define r values[0]
#define g values[1]
#define b values[2]
};
color c;
c.r = 0.5f;
The following has the right semantics except it allocates space in the struct for the 3 references:
struct color : public vec3f {
float& r;
float& g;
float& b;
color() : r(values[0]), g(values[1]), b(values[2]) { }
};
Is there a way to get this compile-time name substitution without increasing the size of the struct?
How about this?
struct vec3f {
float[3] values;
};
struct color : public vec3f
{
float& r() { return values[0]; }
float& g() { return values[1]; }
float& b() { return values[2]; }
const float& r() const { return values[0]; }
const float& g() const { return values[1]; }
const float& b() const { return values[2]; }
};
I am not sure that you want to use inheritance in this case. You might be better of with a plain old union type:
typedef float vec3f[3];
union color {
vec3f values;
struct {
float r;
float g;
float b;
};
};
color c;
c.values[0] = 10;
assert( c.r == 10 );
As it happens, I first saw a really neat trick for this several years ago.
The idea is that you give the class named variables in order, and then also have a static const member of array-of-pointer-to-member type. The operator[] is overloaded to look up the appropriate pointer-to-member, use it to select the member from this, and return a reference.
This works because pointer-to-members are not ordinary pointers; they're a little more magical than that. (This is what enables you to create un-bound pointers to member functions, and why they can't be used where plain function pointers are expected).
It also means that you don't have to use any casting tricks, rely on any kinds of alignment, non-portable anonymous-union behaviour, or memory layout guarantees, and you still get to refer to the components of the structure as named fields instead of via accessor functions.
ALTERNATIVE 1
You always create a temporary when you want a variable alias. With a good optimizer you will hardly see any performance difference.
struct vec3f
{
float values[3];
};
struct tempvec
{
float &r;
float &g;
float &b;
tempvec( vec3f& bar )
:r(bar.values[0])
, g(bar.values[1])
, b(bar.values[2]){}
};
int main()
{
vec3f temp;
temp.values[0] = 2.40f;
//when you want to alias values[0] as r do this
tempvec(temp).r = 42;
tempvec(temp).g = 42;
return 0;
}
ALTERNATIVE 2
If you can verify that memory layout of vec3f and vec3c is the same on your platform and OS.. taking into account padding/alignment etc... you can do
struct vec3f
{
float values[3];
};
struct vec3c
{
float r,g,b;
};
int main()
{
vec3f temp;
temp.values[0] = 2.40f;
vec3c* alias = reinterpret_cast<vec3c*>(&temp);
alias->r = 4.2f;
alias->g = 4.2f;
alias->b = 4.2f;
return 0;
}

advice for static template class

I have this problem (histogramming). I've a real space: [a,b] partitioned in some way ([a0=a, a1, a2, ..., b]). The partitioning may be with equal space (a1 - a0 = a2 - a1 = ...) or variables.
I need a class that handle this, with some methods to say given a value in which bin of the partition it belongs; other methods to find the center of a particular bin and more.
During the program I don't like to instantiate a class only to call these simple function like
Binner binner(binning);
binner.get_bin(1.3);
binner.get_centerbin(2);
so I tried to write a static class using template to do something like that:
Binner<binning>::get_bin(1.3);
Binner<binning>::get_centerbin(2);
is it a good idea? There are other way to do it? Now I've free functions like
double get_bin(double bin, Binning binning); // a lot of if/else inside
but I think it's too error prone.
Here my implementation:
enum Binning {CELL, LARGE, BE};
const double binning_LARGE[] = {0, 1.2, 1.425, 1.550, 1.800, 2.5};
const double binning_BE[] = {0, 1.425, 1.550, 2.5};
template<Binning binning>
class Binner
{
public:
static const double* bins;
static const int n;
static int get_bin(double value);
};
template<> const double* myclass<LARGE>::bins = binning_LARGE;
template<> const double* myclass<BE>::bins = binning_BE;
template<> const int myclass<LARGE>::n = sizeof(binning_LARGE) / sizeof(double);
template<> const int myclass<BE>::n = sizeof(binning_BE) / sizeof(double);
template<Binning binning> int myclass<binning>::get_bin(double value)
{
return find_if(bins, bins + n,
bind2nd(greater<double>(), value)) - bins - 1;
}
template<> int myclass<CELL>::get_bin(double value)
{
return static_cast<int>(value / 0.025);
}
is it a good implementation / design?
Is there a way to avoid the n field using std::vector? How?
Is there a way to parametrize the 0.025? I know that double can't be template parameter but can I write something similar to this:
Binner<0.025> binner;
other / advices?
Edit:
For the third point Why I can't do that:
template<Binning binning, int N=100>
class Binner
{
public:
static const double* bins;
static const int n;
static int bin(double value);
};
...
template<Binning binning, int N> int Binner<CELL, N>::bin(double value)
{
return static_cast<int>(value / (2.5 / N));
}
IMHO, your design is ok, if you do not want to instantiate a class. Indeed, it seems a kind of template metaprogramming to me. Whether this makes sense depends on how you are planning to reuse this template.
Using a std::vector would allow you to get rid of the variable to hold the array size, for sure. Now, if this is good for your design, I don't know... it would move some complexity out of your template definition, to the binning definition (which now you can initialize very simply)...
Finally, you can instantiate your template passing a constant to it:
template < Binning binning, unsigned long N, unsigned long M>
class ... {
<using N>
}
have you considered a traits class? Typically if you have static information that you want to separate from the behaviour in a class, you might consider creating a traits class that encapsulates that.
So I'd start with the default behaviour:
enum Binning {CELL, LARGE, BE};
template <Binning binning>
struct BinTraits
{
// default behaviour
int get_bin(double value) { return value / 0.025; }
};
Then I'd provide the specialisations:
const double binning_LARGE[] = {0, 1.2, 1.425, 1.550, 1.800, 2.5};
const double binning_BE[] = {0, 1.425, 1.550, 2.5};
template <typename RandomAccessCollectionT>
int get_bin_impl(double value, RandomAccessCollectionT collection, unsigned size)
{
return find_if(collection, collection + size,
bind2nd(greater<double>(), value)) - collection - 1;
}
template <>
struct BinTraits<LARGE>
{
int get_bin(double value) { return get_bin_impl(value, binning_LARGE, sizeof(binning_LARGE) / sizeof(binning_LARGE[0])); }
};
template <>
struct BinTraits<BE>
{
int get_bin(double value) { return get_bin_impl(value, binning_BE, sizeof(binning_BE) / sizeof(binning_BE[0])); }
};
Then I'd put the actual container behaviour in another class that requires binning behaviour (lets call it HashTable):
template <typename BinTraits>
class HashTable
{
public:
void insert(double value)
{
int bin = BinTraits::get_bin(value);
_bins[bin].insert(value);
}
// _bin is a multimap or something
};
Looking at the usage of find_if and bind2nd as well as functors, it seems as if you are quite knowledgeable about STL and some advanced C++ concepts; yet, what you are trying to do seems to be over-engineering. While I can't fully understand what you are trying to do but it seems that you could do away with templates completely and use just a class (instantiated with different values) and method parameters.