Recusion and Templates in C++ - c++

I try to compute derivatives using Tangent mode. I tried to implement it using recursion.
I got the following problem: I got a recursion with Templates which compiles forever.
template <typename T>
void dern(int n, const T &x, T &dy)
{
using DCO_T = typename dco::gt1s<T>::type;
DCO_T _x, _y;
dco::value(_x) = x;
dco::derivative(_x) = 1;
if (n > 1)
{
dern(--n, _x, _y);
}
else
{
f(_x, _y);
}
dy = dco::derivative(_y);
}
if I try to write them out it works perfectly fine:
template <typename T>
void der1(const T &x, T &dy)
{
using DCO_T = typename dco::gt1s<T>::type;
DCO_T _x, _y;
dco::value(_x) = x;
dco::derivative(_x) = 1;
f(_x, _y);
dy = dco::derivative(_y);
}
template <typename T>
void der2(const T &x, T &dy)
{
using DCO_T = typename dco::gt1s<T>::type;
DCO_T _x, _y;
dco::value(_x) = x;
dco::derivative(_x) = 1;
der1(_x, _y);
dy = dco::derivative(_y);
}
template <typename T>
void der3(const T &x, T &dy)
{
using DCO_T = typename dco::gt1s<T>::type;
DCO_T _x, _y;
dco::value(_x) = x;
dco::derivative(_x) = 1;
der2(_x, _y);
dy = dco::derivative(_y);
}
template <typename T>
void der4(const T &x, T &dy)
{
using DCO_T = typename dco::gt1s<T>::type;
DCO_T _x, _y;
dco::value(_x) = x;
dco::derivative(_x) = 1;
der3(_x, _y);
dy = dco::derivative(_y);
}
My supervisor thinks it doesn't work because of the template. Does anyone know a fix?

n should be a compile time parameter passed as template argument.
template <int n, typename T>
void dern(const T &x, T &dy)
{
using DCO_T = typename dco::gt1s<T>::type;
DCO_T _x, _y;
dco::value(_x) = x;
dco::derivative(_x) = 1;
if constexpr (n > 1) {
dern<n - 1>(_x, _y);
} else {
f(_x, _y);
}
dy = dco::derivative(_y);
}
A compile time recursion can't depend on a runtime variable.
Call it with, e.g.
dern<4>(x, y);

Related

Easiest way to deduce templates

As an example, I have the following function template:
template <typename X, typename Y, typename Z>
void f(X &x, Y &y, Z &z) { ... }
I need to write a user interface in the form of
void fxyz(std::string optionX, std::string optionY, std::string optionZ)
Here, optionX, optionY, optionZ can be "x1" or "x2", "y1" or "y2", "z1" or "z2" respectively. Every option corresponds to a different type, i.e., X1, X2, Y1, ... .Currently I implemented it like this:
template <typename Y, typename Z>
void fx(std::string &optionX, Y &y, Z &z)
{
if (optionX == "x1") {
X1 x; f <X1, Y, Z> (x, y, z); }
else {
X2 x; f <X2, Y, Z> (x, y, z); }
}
template <typename Z>
void fxy(std::string &optionX, std::string &optionY, Z &z)
{
if (optionY == "y1") {
Y1 y; fx <Y1, Z> (optionX, y, z); }
else {
Y2 y; fx <Y2, Z> (optionX, y, z); }
}
void fxyz(std::string &optionX, std::string &optionY, std::string &optionZ)
{
if (optionZ == "z1") {
Z1 z; fxy <Z1> (optionX, optionY, z); }
else {
Z2 z; fxy <Z2> (optionX, optionY, z); }
}
This seems a lot of work especially if there are more template parameters. Any easier way to achieve what I want?
Thanks!
Map into variants, then visit them.
std::variant<X1, X2> choose_X(std::string_view choice) {
if(choice == "x1") return X1();
else if(choice == "x2") return X2();
}
std::variant<Y1, Y2> choose_Y(std::string_view choice) {
if(choice == "y1") return Y1();
else if(choice == "y2") return Y2();
}
std::variant<Z1, Z2> choose_Z(std::string_view choice) {
if(choice == "z1") return Z1();
else if(choice == "z2") return Z2();
}
You are not getting out of writing some set of rules to get from strings to objects, of course. A possible variation is
std::map<std::string, std::function<std::variant<X1, X2>()>> choices_X{
{"x1", []() { return X1(); }},
{"x2", []() { return X2(); }}
};
Then simply
std::string choice_X, choice_Y, choice_Z;
std::visit(
[](auto&&... xs) -> decltype(auto) { return f(std::forward<decltype(xs)>(xs)...); },
choose_X(choice_X), choose_Y(choice_Y), choose_Z(choice_Z)
);
O(n^2) code length is now O(n) code length (in number of parameters).

C++ keep force driven entities in the window

I have a window application of 1024 width and 768 height and contains a bunch of meteorites, ships and boats. The meteorites freely roam across the window driven by forces.
The forces are: random position, towards/away from boat, towards/away from ship and cohesion, seperation, alignment to other meteorites
I feel like the forces are not fully working since they sometimes move off the screen and move with inverted velocity eg: they are roaming from top right straight to top left and when reached go straight to bottom left.
Are my calculations correct or did I mess up something at the forces?
Meteorite header:
#include <chrono>
#include <cmath>
#include <array>
#include <random>
#include <algorithm>
using scalar = float;
template <typename Scalar> class basic_vector2d {
public:
constexpr basic_vector2d() noexcept = default;
constexpr basic_vector2d(Scalar x, Scalar y) noexcept : x_{ x }, y_{ y } {}
constexpr Scalar x() const noexcept { return x_; }
constexpr void x(Scalar newX) noexcept { x_ = newX; }
constexpr Scalar y() const noexcept { return y_; }
constexpr void y(Scalar newY) noexcept { y_ = newY; }
constexpr bool operator==(basic_vector2d other) const noexcept {
return x_ == other.x_ && y_ == other.y_;
}
constexpr bool operator!=(basic_vector2d other) const noexcept {
return x_ != other.x_ || y_ != other.y_;
}
constexpr basic_vector2d& operator+=(basic_vector2d other) noexcept {
x_ += other.x_;
y_ += other.y_;
return *this;
}
constexpr basic_vector2d& operator-=(basic_vector2d other) noexcept {
x_ -= other.x_;
y_ -= other.y_;
return *this;
}
constexpr basic_vector2d& operator*=(Scalar s) noexcept {
x_ *= s;
y_ *= s;
return *this;
}
constexpr basic_vector2d& operator/=(Scalar s) noexcept {
x_ /= s;
y_ /= s;
return *this;
}
private:
Scalar x_{};
Scalar y_{};
};
template <typename Scalar>
constexpr basic_vector2d<Scalar> operator-(basic_vector2d<Scalar> a,
basic_vector2d<Scalar> b) {
return { a.x() - b.x(), a.y() - b.y() };
}
template <typename Scalar>
constexpr basic_vector2d<Scalar> operator+(basic_vector2d<Scalar> a,
basic_vector2d<Scalar> b) {
return { a.x() + b.x(), a.y() + b.y() };
}
template <typename Scalar>
constexpr basic_vector2d<Scalar> operator*(basic_vector2d<Scalar> v, scalar s) {
return v *= s;
}
template <typename Scalar>
constexpr basic_vector2d<Scalar> operator*(scalar s, basic_vector2d<Scalar> v) {
return operator*(v, s);
}
template <typename Scalar>
constexpr basic_vector2d<Scalar> operator/(basic_vector2d<Scalar> v, scalar s) {
return v /= s;
}
template <typename Scalar>
constexpr basic_vector2d<Scalar> operator/(scalar s, basic_vector2d<Scalar> v) {
return operator/(v, s);
}
template <typename Scalar>
constexpr scalar dot(basic_vector2d<Scalar> a, basic_vector2d<Scalar> b) {
return a.x() * b.x() + a.y() * b.y();
}
template <typename Scalar> constexpr auto norm(basic_vector2d<Scalar> p) {
return std::sqrt(dot(p, p));
}
template <typename Scalar>
constexpr basic_vector2d<Scalar> normalize(basic_vector2d<Scalar> p) {
auto ls = norm(p);
return { p.x() / ls, p.y() / ls };
}
using vector2d = basic_vector2d<scalar>;
template <typename T> class basic_size {
public:
constexpr basic_size() noexcept = default;
constexpr basic_size(T width, T height) noexcept
: width_{ width }, height_{ height } {}
constexpr T width() const noexcept { return width_; }
constexpr T height() const noexcept { return height_; }
constexpr void width(T new_width) noexcept { width_ = new_width; }
constexpr void height(T new_height) noexcept { height_ = new_height; }
constexpr basic_size& operator*=(T x) {
width(width() * x);
height(height() * x);
return *this;
}
private:
T width_{};
T height_{};
};
using size = basic_size<scalar>;
template <typename Scalar> class basic_rectangle {
public:
constexpr basic_rectangle(basic_vector2d<Scalar> top_left,
basic_size<Scalar> size)
: top_left_{ top_left }, size_{ size } {}
constexpr basic_vector2d<Scalar> const& top_left() const noexcept {
return top_left_;
}
constexpr basic_size<Scalar> const& size() const noexcept { return size_; }
private:
basic_vector2d<Scalar> top_left_;
basic_size<Scalar> size_;
};
using rectangle = basic_rectangle<scalar>;
inline float to_seconds(std::chrono::nanoseconds dt) {
return std::chrono::duration_cast<std::chrono::duration<float>>(dt).count();
}
class meteorite {
public:
meteorite(int id, vector2d location);
int id;
/*!
* Called every tick
* \param dt the time that has passed since the previous tick
*/
void act(std::chrono::nanoseconds dt);
vector2d location() const { return location_; }
std::vector<vector2d> random_meteorite_locations(std::size_t n);
private:
vector2d velocity;
scalar max_velocity;
vector2d location_;
vector2d acceleration;
void location(vector2d loc) { location_ = loc; }
void random_position_force();
void screen_force(std::chrono::nanoseconds dt);
void move(std::chrono::nanoseconds dt);
void add_force(vector2d force);
void island_avoidance();
};
Meteorite source:
#include "meteorite.h"
meteorite::meteorite(int id, vector2d location) : id(id), velocity{ 0, 0 }, max_velocity(0.15), acceleration{ 0, 0 }, location_(location) {}
void meteorite::act(std::chrono::nanoseconds dt) {
move(dt);
}
void meteorite::move(std::chrono::nanoseconds dt) {
this->location(this->location() + velocity);
random_position_force();
screen_force(dt);
this->velocity += this->acceleration * to_seconds(dt);
// prevent velocity from exceeding max_velocity
float velocity_length = std::sqrt((this->velocity.x() * this->velocity.x()) + (this->velocity.y() * this->velocity.y()));
if (velocity_length >= this->max_velocity) {
this->velocity = normalize(this->velocity) * this->max_velocity;
}
/*directions:
* y -1 up
* y 1 down
*
* x 1 right
* x -1 left
*/
// reset acceleration to 0 for the next set of forces to be applied
this->acceleration = vector2d(0, 0);
}
// add force propeling meteorite to a random position
void meteorite::random_position_force() {
float x = (rand() % 100 - 50);
float y = (rand() % 100 - 50);
add_force(this->velocity + vector2d((x / 5), (y / 5)));
}
void meteorite::add_force(vector2d force) {
this->acceleration += force;
}
void meteorite::screen_force(std::chrono::nanoseconds dt)
{
auto new_position = this->location() + (this->velocity + (this->acceleration * to_seconds(dt)));
auto height = 1068 - 32;
auto width = 724 - 32;
if (new_position.x() <= 32) {
vector2d screen_vector = vector2d(0, 0);
if (this->acceleration.x() < 0)
{
screen_vector = vector2d(-this->acceleration.x() * 2, 0);
}
add_force(screen_vector);
}
else if (new_position.x() >= width)
{
vector2d screen_vector = vector2d(0, 0);
if (this->acceleration.x() > 0)
{
screen_vector = vector2d(-this->acceleration.x() * 2, 0);
}
add_force(screen_vector);
}
if (new_position.y() <= 32) {
vector2d screen_vector = vector2d(0, 0);
if (this->acceleration.y() < 0)
{
screen_vector = vector2d(0, -this->acceleration.y() * 2);
}
add_force(screen_vector);
}
else if (new_position.y() >= height)
{
vector2d screen_vector = vector2d(0, 0);
if (this->acceleration.y() > 0)
{
screen_vector = vector2d(0, -this->acceleration.y() * 2);
}
add_force(screen_vector);
}
}
std::vector<vector2d> meteorite::random_meteorite_locations(std::size_t n) {
// from 0x2 to 13x17 = 195
// from 13x0 to 28x9 = 135
// from 20x9 to 32x19 = 120
// from 6x17 to 25x24 = 133
// sum = 583
std::random_device rd{};
std::default_random_engine re{ rd() };
std::uniform_int_distribution<> id{ 0, 583 };
std::uniform_real_distribution<scalar> sd{ 0, 1 };
auto rv = [&](rectangle const& r) {
return r.top_left() + vector2d{ r.size().width() * sd(re),
r.size().height() * sd(re) };
};
std::array<rectangle, 4> rects{
rectangle{vector2d{0.1f, 2}, size{13, 15}},
rectangle{vector2d{13.f, 0.1f}, size{15, 9}},
rectangle{vector2d{20, 9}, size{12, 10}},
rectangle{vector2d{6, 17}, size{17, 6}} };
auto to_index = [](int i) -> std::size_t {
if (i < 195)
return 0;
else if (i < 330)
return 1;
else if (i < 450)
return 2;
else
return 3;
};
std::vector<vector2d> result(n);
std::generate_n(result.begin(), result.size(), [&] {
auto val = id(re);
auto index = to_index(val);
auto rect = rects[index];
return 32 * rv(rect);
});
return result;
}
Main.cpp
#include <iostream>
#include "meteorite.h"
int main()
{
meteorite m = meteorite{ 0, {} };
std::vector<meteorite*> meteorites;
std::vector<vector2d> locations = m.random_meteorite_locations(1);
int i = 1;
for (auto& loc : locations) {
meteorites.push_back(new meteorite(i, loc));
}
auto t_prev = std::chrono::high_resolution_clock::now();
while (true) {
auto t_current = std::chrono::high_resolution_clock::now();
std::chrono::nanoseconds dt = std::chrono::nanoseconds(200);
t_prev = t_current;
for (auto& m : meteorites) {
m->act(dt);
std::cout << m->location().x() << " " << m->location().y() << "\n";
}
}
for (auto& m : meteorites) {
delete m;
}
}
You're computing the new position incorrectly in both places, move() and screen_force(). You're doing s = s0 + (v + a * t), but you should be doing s = s0 + v * t + (a * t^2) / 2.
Here's a working example:
http://cpp.sh/9uu3w

How to check type being assigned to result of call operator?

I'm trying to make a simple matrix class
Relevant parts of "mymat.h"
#ifndef _MYMAT_H_GUARD_
#define _MYMAT_H_GUARD_
#include <iostream>
constexpr auto MYMAT_ERR_UNEXPECTED_TYPE = "Error, unexpected type!";
constexpr auto MYMAT_ERR_CODE_UNEXPECTED_TYPE = 0;
constexpr auto MYMAT_ERR_OUT_OF_BOUND = "Error, out of bound!";
constexpr auto MYMAT_ERR_CODE_OUT_OF_BOUND = 0;
template <typename T>
class MYMAT{
public:
T* data;
int x, y;
public:
MYMAT(int x, int y);
~MYMAT();
template <typename C>
void set(int x, int y, C val);
template<typename C>
bool checkType(C val) const;
void print_mat();
public:
T& operator ()(int x, int y);
private:
bool inRange(int x, int y);
};
#endif // !_MYMAT_H_GUARD_
template<typename T>
inline MYMAT<T>::MYMAT(int x, int y){
this->data = new T[x * y]();
this->x = x;
this->y = y;
}
template<typename T>
inline MYMAT<T>::~MYMAT(){
delete this->data;
}
template<typename T>
inline void MYMAT<T>::print_mat(){
int x, y;
for (y = 0; y < this->y; y++)
{
for (x = 0; x < this->x; x++)
{
std::cout << this->data[y * this->x + x] << ' ';
}
std::cout << std::endl;
}
std::cout << std::endl;
}
template<typename T>
inline bool MYMAT<T>::inRange(int x, int y){
return !((x < 1) && (x > this->x) && (y < 1) && (y > this->y));
}
template<typename T>
template<typename C>
inline void MYMAT<T>::set(int x, int y, C val){
if (this->checkType(val)) {
if (this->inRange(x, y)) {
this->data[(y - 1) * this->x + (x - 1)] = val;
}
else {
std::cout << MYMAT_ERR_OUT_OF_BOUND;
exit(MYMAT_ERR_CODE_OUT_OF_BOUND);
}
}
else {
std::cout << MYMAT_ERR_UNEXPECTED_TYPE;
exit(MYMAT_ERR_CODE_UNEXPECTED_TYPE);
}
}
template<typename T>
inline T& MYMAT<T>::operator()(int x, int y)
{
return this->data[this->x * (y - 1) + (x - 1)];
}
template<typename T>
template<typename C>
inline bool MYMAT<T>::checkType(C val) const
{
return std::is_same_v<T, C>;
}
And below is how I call matrix and use set method
#include <iostream>
#include "mymat.h"
int main()
{
MYMAT<int> m(3, 3);
m.set(2, 2, 500);
m.print_mat();
m.set(2, 2, 500.0);
m.print_mat();
}
It prints
0 0 0
0 500 0
0 0 0
Error, unexpected type!
But when call operator is used:
#include <iostream>
#include "mymat.h"
int main()
{
MYMAT<int> m(3, 3);
m(2, 2) = 500;
m.print_mat();
m(2, 2) = 500.0;
m.print_mat();
}
It prints:
0 0 0
0 500 0
0 0 0
0 0 0
0 500 0
0 0 0
As you see, the value is casted from double to int.
How can I apply the condition in set() for call operator?
To achieve what you want:
m(2, 2) = 500.0; // do custom checks for conversions from
// right hand side to left hand side
returning a T& from operator() is not going to work, because you have no control over implicit conversions to T. In this case, you can't prevent the conversion from double to int.
Instead, you can return a type from operator() that you write yourself, so you have all the control you need over implicit conversions. This type needs to hold onto the information on the left hand side, which is the this pointer of m, and the arguments to operator(). It only needs to support operator= to check for implicit conversions from the right hand side:
private:
struct Wrapper
{
MYMAT *t; // holds onto the this pointer
int x, y;
template <typename C>
void operator=(C val)
{
t->set(x, y, val); // uses MYMAT::set to do the conversion checking
}
};
Now you can declare your operator() like this:
public:
Wrapper operator ()(int x, int y);
and define it like this:
template<typename T>
inline auto MYMAT<T>::operator()(int x, int y) -> Wrapper
{
return {this, x, y};
}
Here's a demo.

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())...);
}

Member initializer does not name a non-static data member

I am new to C++ and trying to get an open source C++ project to compile in x-code. The last two lines of this code:
template<typename T>
struct TVector3 : public TVector2<T> {
T z;
TVector3(T _x = 0.0, T _y = 0.0, T _z = 0.0)
: TVector2(_x, _y), z(_z)
are throwing the error: Member initializer does not name a non-static data member
Based on (member initializer does not name a non-static data member or base class), I tried changing the code to this:
template<typename T>
struct TVector3 : public TVector2<T> {
T z;
TVector3(T _x = 0.0, T _y = 0.0, T _z = 0.0)
: TVector2(_x, _y)
{ z(_z);}
But I am getting the same error. Here is the code for the super-class, Vector2. How can I resolve this error?
struct TVector2 {
T x, y;
TVector2(T _x = 0.0, T _y = 0.0)
: x(_x), y(_y)
{}
double Length() const {
return sqrt(static_cast<double>(x*x + y*y));
}
double Norm();
TVector2<T>& operator*=(T f) {
x *= f;
y *= f;
return *this;
}
TVector2<T>& operator+=(const TVector2<T>& v) {
x += v.x;
y += v.y;
return *this;
}
TVector2<T>& operator-=(const TVector2<T>& v) {
x -= v.x;
y -= v.y;
return *this;
}
};
Inside a class template, only its own name is injected for use without template arguments. You need this:
template<typename T>
struct TVector3 : public TVector2<T> {
T z;
TVector3(T _x = 0.0, T _y = 0.0, T _z = 0.0)
: TVector2<T>(_x, _y), z(_z)