Using function pointer forward declaration as lamba declaration - c++

What's the closest I can get to something like this?
.h:
typedef bool (*DoWorkFunc)(uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass2& c2);
void DoWork(DoWorkFunc func);
.cpp:
bool MyClass::MyFunc(uint32_t val) {
DoWork(DoWorkFunc { return c2.mVal < c1.mVal + fParam1 + fParam2; } );
auto f1 = DoWorkFunc { return (bParam ? dParam1 : c1.mVal) < mVal; };
auto f2 = DoWorkFunc { return ((dParam1 & dParam2) == 0) == bParam; };
auto f = val < 3 ? f1: f2;
DoWork(f);
}
This is the closest clean solution I've been able to get, which requires a mostly copy-pasted solution for the lambda forward declaration.
.h:
typedef bool (*DoWorkFunc)(uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass2& c2);
#define DoWorkLambda [](uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass2& c2) -> bool
void DoWork(DoWorkFunc func);
.cpp:
bool MyClass::MyFunc(uint32_t val) {
DoWork(DoWorkLambda { return c2.mVal < c1.mVal + fParam1 + fParam2; } );
auto f1 = DoWorkLambda { return (bParam ? dParam1 : c1.mVal) < mVal; };
auto f2 = DoWorkLambda { return ((dParam1 & dParam2) == 0) == bParam; };
auto f = val < 3 ? f1: f2;
DoWork(f);
}
This works alright for one-off solution, but ends up with a pretty messy header for multiple functions declarations
.h:
typedef bool (*DoWorkFunc1)(uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass2& c2);
#define DoWorkLambda1 [](uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass2& c2) -> bool
void DoWork1(DoWorkFunc1 func);
typedef bool (*DoWorkFunc2)(uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass3& c2);
#define DoWorkLambda2 [](uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass3& c2) -> bool
void DoWork2(DoWorkFunc2 func);
...
For reference, this is what the code looks like without the preprocessor:
.h:
typedef bool (*DoWorkFunc)(uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass2& c2);
void DoWork(DoWorkFunc func);
.cpp:
bool MyClass::MyFunc(uint32_t val) {
DoWork([](uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass2& c2) -> bool
{
return c2.mVal < c1.mVal + fParam1 + fParam2;
}
);
auto f1 = [](uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass2& c2) -> bool
{
return (bParam ? dParam1 : c1.mVal) < mVal;
};
auto f2 = [](uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass2& c2) -> bool
{
return ((dParam1 & dParam2) == 0) == bParam;
};
auto f = val < 3 ? f1: f2;
DoWork(f);
}

It should be possible to assign a lambda function to the equivalent raw function pointer, but ONLY if it does NOT use the scope arguments - i.e. the square brackets in the lambda declaration MUST be empty.
So you should be able to declare the function type. The using syntax is easiest:
using DoWorkFnType =bool (uint32_t , uint32_t , bool , float , float , MyClass& , MyClass2& );
void DoWork(DoWorkFnType* fn);
bool MyClass::MyFunc(uint32_t val) {
DoWorkFnType* f1 = [](uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass2& c2) -> bool
{
return (bParam ? dParam1 : c1.mVal) < mVal;
};
DoWorkFnType* f2 = [](uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass2& c2) -> bool
{
return ((dParam1 & dParam2) == 0) == bParam;
};
auto f = val < 3 ? f1: f2;
DoWork(f);
}
void DoWork(DoWorkFnType* fn)
{
bool res= fn(arg1,arg2,arg3,arg4,arg5.arg6,arg7);
}
If your lambda uses the local scope then only std::function will work to pass the lambda to a child function.
It is not clear at all from your code what you expect DoWork to do, or how it gathers the 7 argument values needed to call f, so I will need to leave it there.

.h:
struct DoWorkParams {
uint32_t dParam1;
uint32_t dParam2;
bool bParam;
float fParam1;
float fParam2;
MyClass& c1;
MyClass2& c2;
};
typedef bool (*DoWorkFunc)(DoWorkParams);
void DoWork(DoWorkFunc func);
.cpp:
bool MyClass::MyFunc(uint32_t val) {
DoWork([](auto p) { return p.c2.mVal < p.c1.mVal + p.fParam1 + p.fParam2; } );
auto f1 = [](auto p) { return (p.bParam ? p.dParam1 : p.c1.mVal) < p.mVal; };
auto f2 = [](auto p) { return ((p.dParam1 & p.dParam2) == 0) == p.bParam; };
auto f = val < 3 ? f1: f2;
DoWork(f);
}
in c++11 you need to change auto p to DoWorkParams p, but the auto feature of lambdas was one of the first c++14 features that compilers supported, so it probably works.
If multiple different functions share parameters, you can use inheritance.
struct DoWorkBaseParams {
uint32_t dParam1;
uint32_t dParam2;
bool bParam;
float fParam1;
float fParam2;
};
struct DoWorkParams1:DoWorkBaseParams {
MyClass& c1;
MyClass2& c2;
};
struct DoWorkParams2:DoWorkBaseParams {
MyClass& c1;
MyClass3& c3;
};
etc

Related

Nonlinear least-squares fitting with two independent variables in C++: implementing GSL algorithm

Following up to a previous question I asked in Fixing parameters of a fitting function in Nonlinear Least-Square GSL (successfully answered by #zkoza), I would like to implement an algorithm that can fit data to a non-linear function, by fixing some of its parameters while leaving other parameters to change for finding the best fit to the data. The difference to my previous question is that I want to have two independent variables instead of one independent variable.
Non-linear function used to fit the data
double gaussian(double x, double b, double a, double c)
{
const double z = (x - b) / c;
return a * std::exp(-0.5 * z * z);
}
In my previous question I was considering that x was the only independent variable. Now I would like to consider two independent variables, x and b.
The original algorithm used to fit a non-linear function using only one independent variable (while fixing variable a) is a C++ wrapper of the GSL nonlinear least-squares algorithm (borrowed from https://github.com/Eleobert/gsl-curve-fit/blob/master/example.cpp):
template <typename F, size_t... Is>
auto gen_tuple_impl(F func, std::index_sequence<Is...> )
{
return std::make_tuple(func(Is)...);
}
template <size_t N, typename F>
auto gen_tuple(F func)
{
return gen_tuple_impl(func, std::make_index_sequence<N>{} );
}
template <class R, class... ARGS>
struct function_ripper {
static constexpr size_t n_args = sizeof...(ARGS);
};
template <class R, class... ARGS>
auto constexpr n_params(R (ARGS...) )
{
return function_ripper<R, ARGS...>();
}
auto internal_solve_system(gsl_vector* initial_params, gsl_multifit_nlinear_fdf *fdf,
gsl_multifit_nlinear_parameters *params) -> std::vector<double>
{
// This specifies a trust region method
const gsl_multifit_nlinear_type *T = gsl_multifit_nlinear_trust;
const size_t max_iter = 200;
const double xtol = 1.0e-8;
const double gtol = 1.0e-8;
const double ftol = 1.0e-8;
auto *work = gsl_multifit_nlinear_alloc(T, params, fdf->n, fdf->p);
int info;
// initialize solver
gsl_multifit_nlinear_init(initial_params, fdf, work);
//iterate until convergence
gsl_multifit_nlinear_driver(max_iter, xtol, gtol, ftol, nullptr, nullptr, &info, work);
// result will be stored here
gsl_vector * y = gsl_multifit_nlinear_position(work);
auto result = std::vector<double>(initial_params->size);
for(int i = 0; i < result.size(); i++)
{
result[i] = gsl_vector_get(y, i);
}
auto niter = gsl_multifit_nlinear_niter(work);
auto nfev = fdf->nevalf;
auto njev = fdf->nevaldf;
auto naev = fdf->nevalfvv;
// nfev - number of function evaluations
// njev - number of Jacobian evaluations
// naev - number of f_vv evaluations
//logger::debug("curve fitted after ", niter, " iterations {nfev = ", nfev, "} {njev = ", njev, "} {naev = ", naev, "}");
gsl_multifit_nlinear_free(work);
gsl_vector_free(initial_params);
return result;
}
template<auto n>
auto internal_make_gsl_vector_ptr(const std::array<double, n>& vec) -> gsl_vector*
{
auto* result = gsl_vector_alloc(vec.size());
int i = 0;
for(const auto e: vec)
{
gsl_vector_set(result, i, e);
i++;
}
return result;
}
template<typename C1>
struct fit_data
{
const std::vector<double>& t;
const std::vector<double>& y;
// the actual function to be fitted
C1 f;
};
template<typename FitData, int n_params>
int internal_f(const gsl_vector* x, void* params, gsl_vector *f)
{
auto* d = static_cast<FitData*>(params);
// Convert the parameter values from gsl_vector (in x) into std::tuple
auto init_args = [x](int index)
{
return gsl_vector_get(x, index);
};
auto parameters = gen_tuple<n_params>(init_args);
// Calculate the error for each...
for (size_t i = 0; i < d->t.size(); ++i)
{
double ti = d->t[i];
double yi = d->y[i];
auto func = [ti, &d](auto ...xs)
{
// call the actual function to be fitted
return d->f(ti, xs...);
};
auto y = std::apply(func, parameters);
gsl_vector_set(f, i, yi - y);
}
return GSL_SUCCESS;
}
using func_f_type = int (*) (const gsl_vector*, void*, gsl_vector*);
using func_df_type = int (*) (const gsl_vector*, void*, gsl_matrix*);
using func_fvv_type = int (*) (const gsl_vector*, const gsl_vector *, void *, gsl_vector *);
template<auto n>
auto internal_make_gsl_vector_ptr(const std::array<double, n>& vec) -> gsl_vector*;
auto internal_solve_system(gsl_vector* initial_params, gsl_multifit_nlinear_fdf *fdf,
gsl_multifit_nlinear_parameters *params) -> std::vector<double>;
template<typename C1>
auto curve_fit_impl(func_f_type f, func_df_type df, func_fvv_type fvv, gsl_vector* initial_params, fit_data<C1>& fd) -> std::vector<double>
{
assert(fd.t.size() == fd.y.size());
auto fdf = gsl_multifit_nlinear_fdf();
auto fdf_params = gsl_multifit_nlinear_default_parameters();
fdf.f = f;
fdf.df = df;
fdf.fvv = fvv;
fdf.n = fd.t.size();
fdf.p = initial_params->size;
fdf.params = &fd;
// "This selects the Levenberg-Marquardt algorithm with geodesic acceleration."
fdf_params.trs = gsl_multifit_nlinear_trs_lmaccel;
return internal_solve_system(initial_params, &fdf, &fdf_params);
}
template <typename Callable, auto n>
auto curve_fit(Callable f, const std::array<double, n>& initial_params, const std::vector<double>& x, const std::vector<double>& y) -> std::vector<double>
{
// We can't pass lambdas without convert to std::function.
//constexpr auto n = 3;//decltype(n_params(f))::n_args - 5;
//constexpr auto n = 2;
assert(initial_params.size() == n);
auto params = internal_make_gsl_vector_ptr(initial_params);
auto fd = fit_data<Callable>{x, y, f};
return curve_fit_impl(internal_f<decltype(fd), n>, nullptr, nullptr, params, fd);
}
In order to fix one of the parameters of the gaussian function, #zkoza proposed to use functors:
struct gaussian_fixed_a
{
double a;
gaussian_fixed_a(double a) : a{a} {}
double operator()(double x, double b, double c) const { return gaussian(x, b, a, c); }
};
And these last lines show how I would create a fake dataset of observed data (with some noise which is normally distributed) and test the fitting curve function with two independent variables, given by the vectors xs and bs.
int main()
{
auto device = std::random_device();
auto gen = std::mt19937(device());
auto xs = linspace<std::vector<double>>(0.0, 1.0, 300);
auto bs = linspace<std::vector<double>>(0.4, 1.4, 300);
auto ys = std::vector<double>(xs.size());
double a = 5.0, c = 0.15;
for(size_t i = 0; i < xs.size(); i++)
{
auto y = gaussian(xs[i], a, bs[i], c);
auto dist = std::normal_distribution(0.0, 0.1 * y);
ys[i] = y + dist(gen);
}
gaussian_fixed_a g(a);
auto r = curve_fit(g, std::array{0.11}, xs, bs, ys);
std::cout << "result: " << r[0] << ' ' << '\n';
std::cout << "error : " << r[0] - c << '\n';
}
Do you have any idea on how I could implement the two-independent variables non-linear fitting?
The solution, as suggested in the comments by #BenVoigt, is to replace the x and b independent variables in the gaussian function with 'one independent variable' given as a vector, whose first element is x and the second element is b.
Also the backbone of the nonlinear fitting needs to be slightly edited. The edits consist:
Replace the fit_data functor with:
struct fit_data
{
const std::vector< vector<double> > &t;
const std::vector<double>& y;
// the actual function to be fitted
C1 f;
};
Such that, the independent variable is no longer a vector but rather a vector of a vector (aka a matrix).
Replace within the function internal_f.
a) double ti = d->t[i] with std::vector<double> ti = d->t[i]
b) auto func = [ti, &d](auto ...xs) with auto func = [ti, &d](auto ...xs_matrix)
c) return d->f(ti, xs...) with return d->f(ti, xs_matrix...)
Replace within curve_fit function:
a) const std::vector<double>& x with const std::vector< vector<double> > &xs_matrix
b) auto fd = fit_data<Callable>{x, y, f} with auto fd = fit_data<Callable>{xs_matrix, y, f}
Whereas the gaussian function, gaussian_fixed_a functor and the fitting function looks like:
double gaussian(std::vector<double> x_vector, double a, double c)
{
const double z = (x_vector[0] - x_vector[1]) / c;
return a * std::exp(-0.5 * z * z);
}
struct gaussian_fixed_a
{
double a;
gaussian_fixed_a(double a) : a{a} {}
double operator()(std::vector<double> x_vector, double c) const { return gaussian(x_vector, a, c); }
};
double fittingTest(const std::vector< vector<double> > &xs_matrix, const std::vector<double> ys, const double a){
gaussian_fixed_a g(a);
auto r = curve_fit(g, std::array{3.0}, xs_matrix, ys);
return r[0]);
}

C++ workaround for doubles as template parameters

I know that doubles can't be template parameters so I'm looking for another way to create a function with several parameters. My current (obviously wrong) code looks like this:
template<double B1, double B2, double B3, double C1, double C2, double C3>
double sellmeier(const double wavelength) {
double refractive_index_sq = 1;
double lambda_sq = std::pow(wavelength, 2);
refractive_index_sq += B1*lambda_sq/(lambda_sq-C1);
refractive_index_sq += B2*lambda_sq/(lambda_sq-C2);
refractive_index_sq += B3*lambda_sq/(lambda_sq-C3);
return refractive_index_sq;
}
Is there a way to create a function that takes several non integral type parameters and one argument without making every parameter an argument too?
What You want here is a policy class which will supply your function with the required values (SpecificConstants).
struct SpecificConstants
{
static constexpr double b1 { 0.6961663 };
static constexpr double b2 { 0.4079426 };
static constexpr double b3 { 0.8974794 };
static constexpr double c1 { 0.0684043 * 0.0684043 };
static constexpr double c2 { 0.1162414 * 0.1162414 };
static constexpr double c3 { 9.896161 * 9.896161 };
};
Your function will only require this policy class (Constants)
template< typename Constants >
double sellmeier( const double wavelength )
{
double refractive_index_sq = 1;
double lambda_sq = std::pow( wavelength, 2 );
refractive_index_sq += Constants::b1 * lambda_sq / ( lambda_sq - Constants::c1 );
refractive_index_sq += Constants::b2 * lambda_sq / ( lambda_sq - Constants::c2 );
refractive_index_sq += Constants::b3 * lambda_sq / ( lambda_sq - Constants::c3 );
return refractive_index_sq;
}
Then, the function can be called like this:
sellmeier< SpecificConstants >( 2.0 );
In c++14 you can do the following, shown with one parameter for brevity's sake:
constexpr double GetB1(int b1Index)
{
switch (b1Index)
{
case 0: return 1.2345;
case 1: return 2.3456;
default: return 3.4567;
}
}
template<int B1Index>
double obviouslyNotSellmeier(const double wavelength) {
return wavelength * GetB1(B1Index);
}
obviouslyNotSellmeier<1>(0.123)
Though it becomes very unfriendly to the caller.
Is there a way to create a function that takes several non integral type parameters and one argument without making every parameter an argument too?
I don't know if it's a good idea but... yes, I suppose you can wrap your floating points values as static constant inside struct's.
Starting from C++11 (constexpr) you can simply define
struct X1 { static constexpr double value { 1.2 }; };
struct X2 { static constexpr double value { 2.3 }; };
struct X3 { static constexpr double value { 3.4 }; };
struct Y1 { static constexpr double value { 4.5 }; };
struct Y2 { static constexpr double value { 5.6 }; };
struct Y3 { static constexpr double value { 6.7 }; };
pass they as template parameter to sellmeier()
sellmeier<X1, X2, X3, Y1, Y2, Y3>(1.0);
and use the value of types inside sellmeier()
template <typename B1, typename B2, typename B3,
typename C1, typename C2, typename C3>
double sellmeier (const double wavelength)
{
double refractive_index_sq = 1;
double lambda_sq = std::pow(wavelength, 2);
refractive_index_sq += B1::value*lambda_sq/(lambda_sq-C1::value);
refractive_index_sq += B2::value*lambda_sq/(lambda_sq-C2::value);
refractive_index_sq += B3::value*lambda_sq/(lambda_sq-C3::value);
return refractive_index_sq;
}
Before C++11 (no constexpr available) the syntax, to define the wrapping structs, is a little more annoying: you have to initialize the const value outside of the body of the structs
struct X1 { static double const value; };
struct X2 { static double const value; };
struct X3 { static double const value; };
struct Y1 { static double const value; };
struct Y2 { static double const value; };
struct Y3 { static double const value; };
double const X1::value = 1.2;
double const X2::value = 2.3;
double const X3::value = 3.4;
double const Y1::value = 4.5;
double const Y2::value = 5.6;
double const Y3::value = 6.7;
As I don't need the parameters at compile time I realized a functor is the better/correct solution:
struct sellmeier {
sellmeier(double B1, double B2, double B3, double C1, double C2, double C3) :
B1(B1), B2(B2), B3(B3), C1(C1), C2(C2), C3(C3) {}
double operator()(const double wavelength) {
double refractive_index_sq = 1;
double lambda_sq = std::pow(wavelength, 2);
refractive_index_sq += B1 * lambda_sq / (lambda_sq - C1);
refractive_index_sq += B2 * lambda_sq / (lambda_sq - C2);
refractive_index_sq += B3 * lambda_sq / (lambda_sq - C3);
return refractive_index_sq;
}
private:
double B1, B2, B3, C1, C2, C3;
};
//functor with sellmeier coefficients for fused quartz
auto sellmeier_fused_quartz = sellmeier(0.6961663, 0.4079426, 0.8974794, 0.0684043*0.0684043, 0.1162414*0.1162414, 9.896161*9.896161);
As I don't need the parameters at compile time I realized a functor is the better/correct solution
In this case, if you can use C++11, you can simply write a lambda
#include <cmath>
int main ()
{
auto B1=0.6961663;
auto B2=0.4079426;
auto B3=0.8974794;
auto C1=0.0684043*0.0684043;
auto C2=0.1162414*0.1162414;
auto C3=9.896161*9.896161;
auto sellmeier = [=] (double const wavelength)
{
double refractive_index_sq = 1;
double lambda_sq = std::pow(wavelength, 2);
refractive_index_sq += B1*lambda_sq/(lambda_sq-C1);
refractive_index_sq += B2*lambda_sq/(lambda_sq-C2);
refractive_index_sq += B3*lambda_sq/(lambda_sq-C3);
return refractive_index_sq;
};
sellmeier(1.0);
}
Starting from C++14, you can simplify (IMHO) as follows
#include <cmath>
int main ()
{
auto sellmeier = [B1=0.6961663,
B2=0.4079426,
B3=0.8974794,
C1=0.0684043*0.0684043,
C2=0.1162414*0.1162414,
C3=9.896161*9.896161] (double const wavelength)
{
double refractive_index_sq = 1;
double lambda_sq = std::pow(wavelength, 2);
refractive_index_sq += B1*lambda_sq/(lambda_sq-C1);
refractive_index_sq += B2*lambda_sq/(lambda_sq-C2);
refractive_index_sq += B3*lambda_sq/(lambda_sq-C3);
return refractive_index_sq;
};
sellmeier(1.0);
}

How to simplify the plus action on boost variant?

I have boost variant type definition:
typedef boost::variant< bool, int, float, double> VariantType;
I want to implement add/subtract/multiply/divide action on it. Take Add class for example. The problem is if adding a new type into VariantType, such as std::string, The Add class must be updated with the new type.
struct Add : public boost::static_visitor<VariantType> {
template <typename T>
T operator() (T a, T b) const {
return a + b;
}
float operator() (int a, float b) const {
return a + b;
}
float operator() (float a, int b) const {
return a + b;
}
double operator() (int a, double b) const {
return a + b;
}
double operator() (double a, int b) const {
return a + b;
}
double operator() (float a, double b) const {
return a + b;
}
double operator() (double a, float b) const {
return a + b;
}
VariantType operator() (bool a, int b) const {
throw std::invalid_argument("bool and int can't Plus");
}
VariantType operator() (bool a, float b) const {
throw std::invalid_argument("bool and float can't Plus");
}
VariantType operator() (bool a, double b) const {
throw std::invalid_argument("bool and double can't Plus");
}
VariantType operator() (int a, bool b) const {
throw std::invalid_argument("int and bool can't Plus");
}
VariantType operator() (float a, bool b) const {
throw std::invalid_argument("float and bool can't Plus");
}
VariantType operator() (double a, bool b) const {
throw std::invalid_argument("double and bool can't Plus");
}
};
usage:
VariantType v1 = 1;
VariantType v2 = 2.1;
VariantType v3 = boost::apply_visitor(Add(), v1, v2);
cout<<boost::get<double>(v3)<<endl; //Print 2.2
The GCC version is 4.8.2; The boost version is 1.57.0;
How to simply the Add class? Thanks.
Just make it a polymorphic functor:
Live On Coliru
#include <boost/variant.hpp>
#include <iostream>
using VariantType = boost::variant<int, float, double, bool>;
struct Add : public boost::static_visitor<VariantType> {
template <typename T, typename U>
auto operator() (T a, U b) const -> decltype(a+b) { return a + b; }
template <typename T> VariantType operator()(bool, T) const { throw std::invalid_argument("Can't to bool"); }
template <typename T> VariantType operator()(T, bool) const { throw std::invalid_argument("Can't add bool"); }
VariantType operator()(bool,bool) const { throw std::invalid_argument("Can't add bools"); }
};
int main() {
std::cout << std::boolalpha;
VariantType specimens[] = { int(42), 3.14f, 3.14, true };
for (auto lhs : specimens)
for (auto rhs : specimens)
{
try {
std::cout << lhs << " + " << rhs << " == " << boost::apply_visitor(Add{}, lhs, rhs) << "\n";
} catch(std::exception const& e) {
std::cout << lhs << " + " << rhs << " ==> " << e.what() << "\n";
}
}
}
Prints:
42 + 42 == 84
42 + 3.14 == 45.14
42 + 3.14 == 45.14
42 + true ==> Can't add bool
3.14 + 42 == 45.14
3.14 + 3.14 == 6.28
3.14 + 3.14 == 6.28
3.14 + true ==> Can't add bool
3.14 + 42 == 45.14
3.14 + 3.14 == 6.28
3.14 + 3.14 == 6.28
3.14 + true ==> Can't add bool
true + 42 ==> Can't to bool
true + 3.14 ==> Can't to bool
true + 3.14 ==> Can't to bool
true + true ==> Can't add bools

conditional equality operator/function based on type

How can one implement a partial comparison operator (or function) for a class, to match a subset of the member variables, based on the specified types? Given the following example:
struct A { int a; bool operator==(A rhs) const { return a==rhs.a; } };
struct B { int b; bool operator==(B rhs) const { return b==rhs.b; } };
struct C { int c; bool operator==(C rhs) const { return c==rhs.c; } };
struct D { int d; bool operator==(D rhs) const { return d==rhs.d; } };
class X
{
public:
X(int a=0, int b=0, int c=0, int d=0)
: _a{a}, _b{b}, _c{c}, _d{d}
{}
A _a;
B _b;
C _c;
D _d;
};
I would like to add support so that the user could compare two X instances based on a subset of the members of X; i.e. something like:
X x1 (1,2,3,4);
X x2 (1,1,2,3);
match<A,B,C,D>( x1, x2 ); /* should return x1._a==x2._a && ... && x1._d==x2._d */
match<A,B,C>( x1, x2 ); /* should return x1._a==x2._a && ... x1._c==x2._c */
match<A,B>( x1, x2 ); /* should return x1._a==x2._a && x1._b==x2._b */
match<A>( x1, x2 ); /* should return x1._a==x2._a */
match<A,D>( x1, x2 ); /* should return x1._a==x2._a && x1._d==x2._d */
The following however fails
template<typename T>
bool match(X x1, X x2) { return false; }
template<>
bool match<A>(X x1, X x2) { return x1._a == x2._a; }
template<>
bool match<B>(X x1, X x2) { return x1._b == x2._b; }
template<>
bool match<C>(X x1, X x2) { return x1._c == x2._c; }
template<>
bool match<D>(X x1, X x2) { return x1._d == x2._d; }
template<typename T, typename... Args>
bool match(X x1, X x2)
{ return match<T>(x1, x2) && match<Args...>(x1, x2); }
With an error message(*)
vard.cc: In function ‘int main()’:
vard.cc:49:35: error: call of overloaded ‘match(X&, X&)’ is ambiguous
std::cout << match<A>( x1, x2 ) << "\n" ;
^
vard.cc:25:6: note: candidate: bool match(X, X) [with T = A]
bool match<A>(X x1, X x2) { return x1._a == x2._a; }
^
vard.cc:37:6: note: candidate: bool match(X, X) [with T = A; Args = {}]
bool match(X x1, X x2)
^
vard.cc: In instantiation of ‘bool match(X, X) [with T = A; Args = {B, C, D}]’:
vard.cc:46:41: required from here
vard.cc:38:18: error: call of overloaded ‘match(X&, X&)’ is ambiguous
{ return match<T>(x1, x2) && match<Args...>(x1, x2); }
^
vard.cc:25:6: note: candidate: bool match(X, X) [with T = A]
bool match<A>(X x1, X x2) { return x1._a == x2._a; }
^
vard.cc:37:6: note: candidate: bool match(X, X) [with T = A; Args = {}]
bool match(X x1, X x2)
^
vard.cc: In instantiation of ‘bool match(X, X) [with T = A; Args = {B, C}]’:
vard.cc:47:39: required from here
vard.cc:38:18: error: call of overloaded ‘match(X&, X&)’ is ambiguous
{ return match<T>(x1, x2) && match<Args...>(x1, x2); }
^
vard.cc:25:6: note: candidate: bool match(X, X) [with T = A]
bool match<A>(X x1, X x2) { return x1._a == x2._a; }
^
vard.cc:37:6: note: candidate: bool match(X, X) [with T = A; Args = {}]
bool match(X x1, X x2)
^
vard.cc: In instantiation of ‘bool match(X, X) [with T = A; Args = {B}]’:
vard.cc:48:37: required from here
vard.cc:38:18: error: call of overloaded ‘match(X&, X&)’ is ambiguous
{ return match<T>(x1, x2) && match<Args...>(x1, x2); }
^
vard.cc:25:6: note: candidate: bool match(X, X) [with T = A]
bool match<A>(X x1, X x2) { return x1._a == x2._a; }
^
vard.cc:37:6: note: candidate: bool match(X, X) [with T = A; Args = {}]
bool match(X x1, X x2)
^
vard.cc:38:44: error: call of overloaded ‘match(X&, X&)’ is ambiguous
{ return match<T>(x1, x2) && match<Args...>(x1, x2); }
^
vard.cc:28:6: note: candidate: bool match(X, X) [with T = B]
bool match<B>(X x1, X x2) { return x1._b == x2._b; }
^
vard.cc:37:6: note: candidate: bool match(X, X) [with T = B; Args = {}]
bool match(X x1, X x2)
^
Why are the calls ambiguous? What would be a correct, clear implementation be? Could this functionality be incorporated within the class's equality operator?
(*) The test program compiled is just a concatenation of the code presented above;
#include <iostream>
struct A { int a; bool operator==(A rhs) const { return a==rhs.a; } };
struct B { int b; bool operator==(B rhs) const { return b==rhs.b; } };
struct C { int c; bool operator==(C rhs) const { return c==rhs.c; } };
struct D { int d; bool operator==(D rhs) const { return d==rhs.d; } };
class X
{
public:
X(int a=0, int b=0, int c=0, int d=0)
: _a{a}, _b{b}, _c{c}, _d{d}
{}
A _a;
B _b;
C _c;
D _d;
};
template<typename T>
bool match(X x1, X x2) { return false; }
template<>
bool match<A>(X x1, X x2) { return x1._a == x2._a; }
template<>
bool match<B>(X x1, X x2) { return x1._b == x2._b; }
template<>
bool match<C>(X x1, X x2) { return x1._c == x2._c; }
template<>
bool match<D>(X x1, X x2) { return x1._d == x2._d; }
template<typename T, typename... Args>
bool match(X x1, X x2)
{ return match<T>(x1, x2) && match<Args...>(x1, x2); }
int main()
{
X x1 (1,2,3,4);
X x2 (0,1,2,3);
X x3 (3,3,3,3);
std::cout << match<A,B,C,D>( x1, x2 ) << "\n" ;
std::cout << match<A,B,C>( x1, x2 ) << "\n" ;
std::cout << match<A,B>( x1, x2 ) << "\n" ;
std::cout << match<A>( x1, x2 ) << "\n" ;
return 0;
}
compiled with clang++ 3.7.0 (g++ (GCC) 5.3.1 gives pretty much the same error).
Here is one idea, using std::tuple to provide all the actual product operations. We just need to expose the class members:
struct A { int a; bool operator==(A rhs) const { return a==rhs.a; } };
struct B { int b; bool operator==(B rhs) const { return b==rhs.b; } };
struct C { int c; bool operator==(C rhs) const { return c==rhs.c; } };
struct D { int d; bool operator==(D rhs) const { return d==rhs.d; } };
class X
{
template <typename> friend struct Get;
public:
X(int a=0, int b=0, int c=0, int d=0)
: _a{a}, _b{b}, _c{c}, _d{d}
{}
A _a;
B _b;
C _c;
D _d;
};
template <typename> struct Get;
template <> struct Get<A> { static const A & get(const X & x) { return x._a; } };
template <> struct Get<B> { static const B & get(const X & x) { return x._b; } };
template <> struct Get<C> { static const C & get(const X & x) { return x._c; } };
template <> struct Get<D> { static const D & get(const X & x) { return x._d; } };
#include <tuple>
template <typename ...Args> bool Match(const X & lhs, const X & rhs)
{
return std::tie(Get<Args>::get(lhs)...) == std::tie(Get<Args>::get(rhs)...);
}
Usage:
#include <iostream>
int main()
{
X x1 (1,2,3,4);
X x2 (1,1,2,3);
std::cout << Match<A, A, A>(x1, x2) << "\n";
std::cout << Match<A, D>(x1, x2) << "\n";
}
If you can use C++14, this is pretty easy using std::tuple.
First, we add a tie method to X to tie all the members:
class X
{
public:
X(int a=0, int b=0, int c=0, int d=0)
: _a{a}, _b{b}, _c{c}, _d{d}
{}
A _a;
B _b;
C _c;
D _d;
std::tuple<A,B,C,D> tie () { return std::tie(_a,_b,_c,_d); }
};
Then we can extract the types we are passed for match from that tuple and compare them:
template<typename... Args>
bool match(X x1, X x2)
{
return std::make_tuple(std::get<Args>(x1.tie())...) ==
std::make_tuple(std::get<Args>(x2.tie())...);
}

Why does this passed-by-value parameter get corrupted? (c++)

I'm passing a ivec2 (2 dimentional int vector) throw multiple methods calls of differnent classes. All by value. However after the first pass it starts to corrupt. Since the vector implementation if part of the library (called visualisation library), I'm guessing I'm doing something wrong.
Here is the callstack:
The parameter in question is pixel. Its created in TesselatedHeightField::getHeightAt(vl::fvec2 uv):
vl::ivec2 pixel = vl::ivec2(
static_cast<int> (std::floor(uv.x() * hfImage_->width())),
static_cast<int> (std::floor(uv.y() * hfImage_->height())));
float patchesHeightPerCent = heightField_->getPatchContainer()->getRelativeHeightAt(pixel);
The debugger tells me that the values of pixel are 177 and 23, which is fine.
Down the callstack in:
float
PatchContainer::getRelativeHeightAt(vl::ivec2 pixel)
{
float relHeight = 0.0;
for (PatchesVector::iterator iter = patches_.begin(); iter != patches_.end(); ++iter)
{
relHeight += (*iter)->getRelativeHeightAt(pixel);
}
return relHeight;
}
the pixel is allready corrupted showing -1073751104 and 177 for its values.
In Patch::getRelativeHeightAt(vl::ivec2 pixel) the values are -1073751204 and -1073751224.
In Patch::inside(vl::ivec2 pixel) the values are -1073751316 and -1208145864 .
about vl::ivec2
Again vl::ivec2 is part of the library.
vl::ivec2 is a type def typedef Vector2<GLint> ivec2;
Here are the contents of the ivec2 implementation. (Party of the library, not created by me).
/**************************************************************************************/
/* */
/* Visualization Library */
/* http://www.visualizationlibrary.com */
/* */
/* Copyright (c) 2005-2010, Michele Bosi */
/* All rights reserved. */
/* */
/* Redistribution and use in source and binary forms, with or without modification, */
/* are permitted provided that the following conditions are met: */
/* */
/* - Redistributions of source code must retain the above copyright notice, this */
/* list of conditions and the following disclaimer. */
/* */
/* - Redistributions in binary form must reproduce the above copyright notice, this */
/* list of conditions and the following disclaimer in the documentation and/or */
/* other materials provided with the distribution. */
/* */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
/* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
/* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
/* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
/* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
/* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
/* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
/* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/* */
/**************************************************************************************/
#ifndef Vector2_INCLUDE_ONCE
#define Vector2_INCLUDE_ONCE
#include <vlCore/OpenGLDefs.hpp>
#include <cmath>
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
#ifdef dot
#undef dot
#endif
#ifdef cross
#undef cross
#endif
namespace vl
{
// trigonometric constants
//! Greek Pi constant using \p double precision.
const double dPi = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093845;
//! Constant to convert degrees into radians using \p double precision.
const double dDEG_TO_RAD = dPi / 180.0;
//! Constant to convert radians into degrees using \p double precision.
const double dRAD_TO_DEG = 180.0 / dPi;
//! Greek Pi constant using \p float precision.
const float fPi = (float)3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093845;
//! Constant to convert degrees into radians using \p float precision.
const float fDEG_TO_RAD = float(dPi / 180.0);
//! Constant to convert radians into degrees using \p float precision.
const float fRAD_TO_DEG = float(180.0 / dPi);
// fast square root
#if VL_FAST_SQUARE_ROOTS == 1
#define VL_FLOAT_SQRT(x) fast_sqrt(x)
#define VL_FLOAT_INVSQRT(x) fast2_inversesqrt(x)
#else
#define VL_FLOAT_SQRT(x) ((float)::sqrt(x))
#define VL_FLOAT_INVSQRT(x) (1.0f/(float)::sqrt(x))
#endif
// fast square root functions, see Dave Eberly's paper and http://www.beyond3d.com/content/articles/8/
inline float fast1_inversesqrt(float x)
{
float xhalf = 0.5f*x;
union { float f; unsigned int i; } num;
num.f = x;
num.i = 0x5f3759df - (num.i>>1);
x = num.f;
x = x*(1.5f - xhalf*x*x); // single iteration, very quick, but very poor precision
return x;
}
inline float fast2_inversesqrt(float x)
{
float xhalf = 0.5f*x;
union { float f; unsigned int i; } num;
num.f = x;
num.i = 0x5f3759df - (num.i>>1);
x = num.f;
x = x*(1.5f - xhalf*x*x);
x = x*(1.5f - xhalf*x*x); // two iterations, sligthtly better precision
return x;
}
inline float fast_sqrt(float x) { if (x == 0.0f) return 0.0f; else return x * fast2_inversesqrt(x); }
/**
* The Vector2 class is a template class that implements a generic 2 components vector, see also vl::fvec2, vl::dvec2, vl::uvec2, vl::ivec2, vl::svec2, vl::usvec2, vl::bvec2, vl::ubvec2.
* \sa Vector4, Vector3, Matrix4, Matrix3, Matrix2
*/
template<typename T_Scalar>
class Vector2
{
public:
typedef T_Scalar scalar_type;
static const int scalar_count = 2;
Vector2(const Vector2& other) { *this = other; }
Vector2() { x() = y() = 0; }
template<class T>
explicit Vector2(const T& other)
{
x() = (T_Scalar)other.x();
y() = (T_Scalar)other.y();
}
explicit Vector2(T_Scalar x, T_Scalar y)
{
mScalar[0] = x;
mScalar[1] = y;
}
T_Scalar* ptr() { return mScalar; }
const T_Scalar* ptr() const { return mScalar; }
const T_Scalar& x() const { return mScalar[0]; }
const T_Scalar& y() const { return mScalar[1]; }
T_Scalar& x() { return mScalar[0]; }
T_Scalar& y() { return mScalar[1]; }
const T_Scalar& r() const { return mScalar[0]; }
const T_Scalar& g() const { return mScalar[1]; }
T_Scalar& r() { return mScalar[0]; }
T_Scalar& g() { return mScalar[1]; }
const T_Scalar& s() const { return mScalar[0]; }
const T_Scalar& t() const { return mScalar[1]; }
T_Scalar& s() { return mScalar[0]; }
T_Scalar& t() { return mScalar[1]; }
Vector2 operator+(const Vector2& other) const
{
return Vector2(x()+other.x(), y()+other.y());
}
Vector2 operator-(const Vector2& other) const
{
return Vector2(x()-other.x(), y()-other.y());
}
Vector2 operator*(const Vector2& other) const
{
return Vector2(x()*other.x(), y()*other.y());
}
Vector2 operator/(const Vector2& other) const
{
return Vector2(x()/other.x(), y()/other.y());
}
Vector2 operator+(T_Scalar val) const
{
return Vector2(x()+val, y()+val);
}
Vector2 operator-(T_Scalar val) const
{
return Vector2(x()-val, y()-val);
}
Vector2 operator*(T_Scalar val) const
{
return Vector2(x()*val, y()*val);
}
Vector2 operator/(T_Scalar val) const
{
return Vector2(x()/val, y()/val);
}
Vector2 operator-() const
{
return Vector2(-x(), -y());
}
Vector2& operator+=(const Vector2& other)
{
*this = *this + other;
return *this;
}
Vector2& operator-=(const Vector2& other)
{
*this = *this - other;
return *this;
}
Vector2& operator*=(const Vector2& other)
{
*this = *this * other;
return *this;
}
Vector2& operator/=(const Vector2& other)
{
*this = *this / other;
return *this;
}
Vector2& operator+=(T_Scalar val)
{
*this = *this + val;
return *this;
}
Vector2& operator-=(T_Scalar val)
{
*this = *this - val;
return *this;
}
Vector2& operator*=(T_Scalar val)
{
*this = *this * val;
return *this;
}
Vector2& operator/=(T_Scalar val)
{
*this = *this / val;
return *this;
}
Vector2& operator=(const Vector2& other)
{
x() = other.x();
y() = other.y();
return *this;
}
Vector2& operator=(T_Scalar val)
{
x() = y() = val;
return *this;
}
bool operator==(const Vector2& other) const
{
return x() == other.x() && y() == other.y();
}
bool operator!=(const Vector2& other) const
{
return !operator==(other);
}
bool operator<(const Vector2& other) const
{
if (x() != other.x())
return x() < other.x();
else
return y() < other.y();
}
T_Scalar& operator[](unsigned i) { return mScalar[i]; }
const T_Scalar& operator[](unsigned i) const { return mScalar[i]; }
T_Scalar length() const { return ::sqrt(x()*x()+y()*y()); }
T_Scalar lengthSquared() const { return x()*x()+y()*y(); }
bool isNull() const { return !x() && !y(); }
const Vector2& normalize(T_Scalar *len=NULL)
{
T_Scalar l = length();
if (len)
*len = l;
if (l)
*this *= (T_Scalar)(1.0/l);
return *this;
}
protected:
T_Scalar mScalar[scalar_count];
};
template<typename T>
inline const Vector2<T> operator*(T val, const Vector2<T>& v)
{
return v * val;
}
//! A 2 components vector with \p GLint precision.
typedef Vector2<GLint> ivec2;
//! A 2 components vector with \p GLuint precision.
typedef Vector2<GLuint> uvec2;
//! A 2 components vector with \p GLfloat precision.
typedef Vector2<GLfloat> fvec2;
//! A 2 components vector with \p GLdouble precision.
typedef Vector2<GLdouble> dvec2;
//! A 2 components vector with \p GLbyte precision.
typedef Vector2<GLbyte> bvec2;
//! A 2 components vector with \p GLubyte precision.
typedef Vector2<GLubyte> ubvec2;
//! A 2 components vector with \p GLshort precision.
typedef Vector2<GLshort> svec2;
//! A 2 components vector with \p GLushort precision.
typedef Vector2<GLushort> usvec2;
#if VL_PIPELINE_PRECISION == 2
//! Defined as: \p 'typedef \p dvec2 \p vec2'. See also \ref VL_PIPELINE_PRECISION.
typedef dvec2 vec2;
#else
//! Defined as: \p 'typedef \p fvec2 \p vec2'. See also \ref VL_PIPELINE_PRECISION.
typedef fvec2 vec2;
#endif
inline float dot(const fvec2& v1, const fvec2& v2) { return v1.x()*v2.x() + v1.y()*v2.y(); }
inline double dot(const dvec2& v1, const dvec2& v2) { return v1.x()*v2.x() + v1.y()*v2.y(); }
inline float dot(const ivec2& v1, const ivec2& v2) { return (float)(v1.x()*v2.x() + v1.y()*v2.y()); }
inline float dot(const uvec2& v1, const uvec2& v2) { return (float)(v1.x()*v2.x() + v1.y()*v2.y()); }
inline float min(float a, float b) { return a < b ? a : b; }
inline double min(double a, double b) { return a < b ? a : b; }
inline int min(int a, int b) { return a < b ? a : b; }
inline unsigned int min(unsigned int a, unsigned int b) { return a < b ? a : b; }
inline float max(float a, float b) { return a > b ? a : b; }
inline double max(double a, double b) { return a > b ? a : b; }
inline int max(int a, int b) { return a > b ? a : b; }
inline unsigned int max(unsigned int a, unsigned int b) { return a > b ? a : b; }
inline float clamp(float x, float minval, float maxval) { return min(max(x,minval),maxval); }
inline double clamp(double x, double minval, double maxval) { return min(max(x,minval),maxval); }
inline int clamp(int x, int minval, int maxval) { return min(max(x,minval),maxval); }
inline unsigned int clamp(unsigned int x, unsigned int minval, unsigned int maxval) { return min(max(x,minval),maxval); }
inline fvec2 min(const fvec2& a, const fvec2& b)
{
return fvec2( a.x() < b.x() ? a.x() : b.x(),
a.y() < b.y() ? a.y() : b.y());
}
inline fvec2 min(const fvec2& a, float b)
{
return fvec2( a.x() < b ? a.x() : b,
a.y() < b ? a.y() : b);
}
inline dvec2 min(const dvec2& a, const dvec2& b)
{
return dvec2( a.x() < b.x() ? a.x() : b.x(),
a.y() < b.y() ? a.y() : b.y());
}
inline dvec2 min(const dvec2& a, double b)
{
return dvec2( a.x() < b ? a.x() : b,
a.y() < b ? a.y() : b);
}
inline ivec2 min(const ivec2& a, const ivec2& b)
{
return ivec2( a.x() < b.x() ? a.x() : b.x(),
a.y() < b.y() ? a.y() : b.y());
}
inline ivec2 min(const ivec2& a, int b)
{
return ivec2( a.x() < b ? a.x() : b,
a.y() < b ? a.y() : b);
}
inline uvec2 min(const uvec2& a, const uvec2& b)
{
return uvec2( a.x() < b.x() ? a.x() : b.x(),
a.y() < b.y() ? a.y() : b.y());
}
inline uvec2 min(const uvec2& a, unsigned int b)
{
return uvec2( a.x() < b ? a.x() : b,
a.y() < b ? a.y() : b);
}
inline fvec2 max(const fvec2& a, const fvec2& b)
{
return fvec2( a.x() > b.x() ? a.x() : b.x(),
a.y() > b.y() ? a.y() : b.y());
}
inline fvec2 max(const fvec2& a, float b)
{
return fvec2( a.x() > b ? a.x() : b,
a.y() > b ? a.y() : b);
}
inline dvec2 max(const dvec2& a, const dvec2& b)
{
return dvec2( a.x() > b.x() ? a.x() : b.x(),
a.y() > b.y() ? a.y() : b.y());
}
inline dvec2 max(const dvec2& a, double b)
{
return dvec2( a.x() > b ? a.x() : b,
a.y() > b ? a.y() : b);
}
inline ivec2 max(const ivec2& a, const ivec2& b)
{
return ivec2( a.x() > b.x() ? a.x() : b.x(),
a.y() > b.y() ? a.y() : b.y());
}
inline ivec2 max(const ivec2& a, int b)
{
return ivec2( a.x() > b ? a.x() : b,
a.y() > b ? a.y() : b);
}
inline uvec2 max(const uvec2& a, const uvec2& b)
{
return uvec2( a.x() > b.x() ? a.x() : b.x(),
a.y() > b.y() ? a.y() : b.y());
}
inline uvec2 max(const uvec2& a, unsigned int b)
{
return uvec2( a.x() > b ? a.x() : b,
a.y() > b ? a.y() : b);
}
inline fvec2 clamp(const fvec2& x, float minval, float maxval) { return min(max(x,minval),maxval); }
inline fvec2 clamp(const fvec2& x, const fvec2& minval, const fvec2& maxval) { return min(max(x,minval),maxval); }
inline dvec2 clamp(const dvec2& x, double minval, double maxval) { return min(max(x,minval),maxval); }
inline dvec2 clamp(const dvec2& x, const dvec2& minval, const dvec2& maxval) { return min(max(x,minval),maxval); }
inline ivec2 clamp(const ivec2& x, int minval, int maxval) { return min(max(x,minval),maxval); }
inline ivec2 clamp(const ivec2& x, const ivec2& minval, const ivec2& maxval) { return min(max(x,minval),maxval); }
inline uvec2 clamp(const uvec2& x, unsigned int minval, unsigned int maxval) { return min(max(x,minval),maxval); }
inline uvec2 clamp(const uvec2& x, const uvec2& minval, const uvec2& maxval) { return min(max(x,minval),maxval); }
}
#endif
Any help is appreciated.
Visualisation Library Homepage
Edit:
I did put a breakpoint at Vector2(const Vector2& other) { *this = other; }.
Here are the debuger results:
This calls:
Vector2& operator=(const Vector2& other)
{
x() = other.x();
y() = other.y();
return *this;
}
Resulting in:
At the end of the copy constructor the debugger yelds vales that are incorrect.
What OS is this? It sounds like a calling convention or structure layout mismatch, which you could easily get if not using the same compiler version and options for all files.
Put a breakpoint in the ivec2 copy constructor and see whether the value are correct there.
You could remove explicit from the copy constructor.
But its explicit to stop pass by value as this is inefficient