I work actually to understand the concept of template and implement a simple one. I manage to almost cases execpt one to code a constructor to copy an instance of same class.
#include <iostream>
// template <typename T>
template <class T>
class vec2 {
private:
static int instance;
T const x;
T const y;
public:
vec2() : x(0), y(0) {
std::cout << "Default constructor" << std::endl;
vec2<T>::instance++;
return;
}
vec2(T const &x, T const &y) : x(x), y(y) {
std::cout << "Parametric constructor" << std::endl;
vec2<T>::instance++;
return;
}
vec2(vec2<T> const & src) {
*this = src;
std::cout << "Copy constructor" << std::endl;
vec2<T>::instance++;
return;
}
~vec2(){
std::cout << "Destructor" << std::endl;
vec2<T>::instance--;
return;
}
vec2 & operator=(vec2 const & rhs) {
this->x = rhs.get_x();
this->y = rhs.get_y();
return *this;
}
// get
static int get_instance() {
return vec2<T>::instance;
}
T get_x() const {
return this->x;
}
T get_y() const {
return this->y;
}
};
template <class T>
std::ostream & operator<<(std::ostream & out, vec2<T> const & rhs) {
out << "[ " << rhs.get_x() << ", " << rhs.get_y() << " ]";
return out;
}
template <class T>
int vec2<T>::instance = 0;
int main() {
vec2<float> a;
vec2<int> b(21, 42);
vec2<float> c(21.21f, 42.42f);
vec2<bool> d(true, false);
vec2<int> e(b);
std::cout << a << std::endl;
std::cout << b << std::endl;
std::cout << c << std::endl;
std::cout << d << std::endl;
std::cout << e << std::endl;
std::cout << "a.get_x(): " << a.get_x() << std::endl;
std::cout << "a.get_y(): " << a.get_y() << std::endl;
std::cout << "b.get_x(): " << b.get_x() << std::endl;
std::cout << "b.get_y(): " << b.get_y() << std::endl;
std::cout << "c.get_x(): " << c.get_x() << std::endl;
std::cout << "c.get_y(): " << c.get_y() << std::endl;
std::cout << "d.get_x(): " << d.get_x() << std::endl;
std::cout << "d.get_y(): " << d.get_y() << std::endl;
return (0);
}
here the error message, but I'm not expert te read it, and i don't understand what i must change in my code. So if anybody I have an idea to help a newbee in C++, that's can be awesome.
clang++ -std=c++11 -Wconversion *.cpp && ./a.out
main.cpp:24:2: error: constructor for 'vec2<int>' must explicitly initialize the
const member 'x'
vec2(vec2<T> const & src) {
^
main.cpp:72:12: note: in instantiation of member function 'vec2<int>::vec2'
requested here
vec2<int> e(b);
^
main.cpp:9:10: note: declared here
T const x;
^
main.cpp:24:2: error: constructor for 'vec2<int>' must explicitly initialize the
const member 'y'
vec2(vec2<T> const & src) {
^
main.cpp:10:10: note: declared here
T const y;
^
main.cpp:38:11: error: cannot assign to non-static data member 'x' with
const-qualified type 'const int'
this->x = rhs.get_x();
~~~~~~~ ^
main.cpp:25:9: note: in instantiation of member function 'vec2<int>::operator='
requested here
*this = src;
^
main.cpp:72:12: note: in instantiation of member function 'vec2<int>::vec2'
requested here
vec2<int> e(b);
^
main.cpp:9:10: note: non-static data member 'x' declared const here
T const x;
~~~~~~~~^
main.cpp:39:11: error: cannot assign to non-static data member 'y' with
const-qualified type 'const int'
this->y = rhs.get_y();
~~~~~~~ ^
main.cpp:10:10: note: non-static data member 'y' declared const here
T const y;
~~~~~~~~^
4 errors generated.
As #Sam Varshavchik said in the comments, the problem is that you don't initialize your const members in your copy-constructor. Here is the correct implementation:
vec2(vec2<T> const & src) : x(src.get_x()), y(src.get_y()) { //<-- initialization of const members
std::cout << "Copy constructor" << std::endl;
vec2<T>::instance++;
return;
}
Also, *this = src; does feel all kinds of wrong.
here my original class code where i make a copy with *this = src and the result work great. So the question why that's work with regular class and not with the template ?
Plus I imagine the behavior with the regular class, the adress stay the same.
And the method to init all member can be complicated if the is a lot members variables in the class ?
main.c
#include "Vec2.hpp"
#include <iostream>
int main() {
Vec2 a;
Vec2 b(21,42);
Vec2 c(a);
std::cout << a << std::endl;
std::cout << "c.get_x(): " << c.get_x() << std::endl;
std::cout << "c.get_y(): " << c.get_y() << std::endl;
std::cout << "b.get_x(): " << b.get_x() << std::endl;
std::cout << "b.get_y(): " << b.get_y() << std::endl;
std::cout << "a.get_x(): " << a.get_x() << std::endl;
std::cout << "a.get_y(): " << a.get_y() << std::endl;
a = b;
std::cout << "a.get_x(): " << a.get_x() << std::endl;
std::cout << "a.get_y(): " << a.get_y() << std::endl;
return 0;
}
Vec2.cpp
#ifndef VEC2_H
# define VEC2_H
#include <iostream>
class Vec2 {
public:
Vec2(); // canonical
Vec2(float const x, float const y);
Vec2(Vec2 const &); // canonical
~Vec2(); // canonical
Vec2 & operator=(Vec2 const & rhs); // canonical
static int get_instance();
float get_x() const ;
float get_y() const ;
private:
static int instance;
float x;
float y;
};
std::ostream & operator<< (std::ostream & out, Vec2 const & rhs);
#endif
vec2.hpp
#include "Vec2.hpp"
#include <iostream>
Vec2::Vec2() : x(0), y(0) {
std::cout << "Default constructor" << std::endl;
Vec2::instance++;
return;
}
Vec2::Vec2(float const x, float const y) : x(x), y(y) {
std::cout << "Parametric constructor" << std::endl;
Vec2::instance++;
return;
}
Vec2::Vec2(Vec2 const & src) {
*this = src;
std::cout << "Copy constructor" << std::endl;
Vec2::instance++;
return;
}
Vec2::~Vec2() {
std::cout << "Destructor" << std::endl;
Vec2::instance--;
return;
}
Vec2 & Vec2::operator=(Vec2 const & rhs) {
this->x = rhs.get_x();
this->y = rhs.get_y();
return *this;
}
int Vec2::get_instance(){
return Vec2::instance;
}
float Vec2::get_x() const {
return this->x;
}
float Vec2::get_y() const {
return this->y;
}
std::ostream & operator<< (std::ostream & out, Vec2 const & rhs) {
out << "[ " << rhs.get_x() << ", " << rhs.get_y() << " ]";
return out;
}
int Vec2::instance = 0;
Related
I wrote a generic class for handling and executing a function pointer. This is a simplified equivalent of std::function and std::bind. To handle member functions I use cast to internal EventHandler::Class type. Question: is it ok to cast it that way? Will it work in all cases when invoking handled function?
template <typename ReturnType, typename... Arguments>
class EventHandler
{
class Class {};
ReturnType (Class::*memberFunction)(Arguments...) = nullptr;
union {
Class *owner;
ReturnType(*function)(Arguments...) = nullptr;
};
public:
EventHandler() = default;
EventHandler(EventHandler &&) = default;
EventHandler(const EventHandler &) = default;
EventHandler &operator=(EventHandler &&) = default;
EventHandler &operator=(const EventHandler &) = default;
EventHandler(ReturnType (*function)(Arguments...)) :
function(function)
{
}
template <typename Owner>
EventHandler(Owner *owner, ReturnType (Owner::*memberFunction)(Arguments...)) :
memberFunction((ReturnType (Class::*)(Arguments...)) memberFunction),
owner((Class *) owner)
{
}
template <typename Owner>
EventHandler(const Owner *owner, ReturnType (Owner::*memberFunction)(Arguments...) const) :
memberFunction((ReturnType (Class::*)(Arguments...)) memberFunction),
owner((Class *) owner)
{
}
ReturnType operator()(Arguments... arguments)
{
return memberFunction ?
(owner ? (owner->*memberFunction)(arguments...) : ReturnType()) :
(function ? function(arguments...) : ReturnType());
}
};
The implementation provides handle for a global function, a member function and a const member function. Obviously there is volatile and const volatile that is not show here for clarity.
EDIT
All the code below is just a representation of all of kinds of supported functions.
class Object
{
public:
double y = 1000;
Object() = default;
Object(double y) : y(y) {}
static void s1(void) { std::cout << "s1()" << std::endl; }
static void s2(int a) { std::cout << "s2(a:" << 10 + a << ")" << std::endl; }
static void s3(int a, float b) { std::cout << "s3(a:" << 10 + a << ", b:" << 10 + b << ")" << std::endl; }
static int s4(void) { std::cout << "s4(): "; return 10 + 4; }
static Object s5(int a) { std::cout << "s5(a:" << 10 + a << "): "; return Object(10 + 5.1); }
static float s6(int a, Object b) { std::cout << "s6(a:" << 10 + a << ", b:" << 10 + b.y << "); "; return 10 + 6.2f; }
void m1(void) { std::cout << "m1()" << std::endl; }
void m2(int a) { std::cout << "m2(a:" << y + a << ")" << std::endl; }
void m3(int a, float b) { std::cout << "m3(a:" << y + a << ", b:" << y + b << ")" << std::endl; }
int m4(void) { std::cout << "m4(): "; return ((int) y) + 4; }
Object m5(int a) { std::cout << "m5(a:" << y + a << "): "; return Object(y + 5.1); }
float m6(int a, Object b) { std::cout << "m6(a:" << y + a << ", b:" << y + b.y << "); "; return ((int) y) + 6.2f; }
void c1(void) const { std::cout << "c1()" << std::endl; }
void c2(int a) const { std::cout << "c2(a:" << y + a << ")" << std::endl; }
void c3(int a, float b) const { std::cout << "c3(a:" << y + a << ", b:" << y + b << ")" << std::endl; }
int c4(void) const { std::cout << "c4(): "; return ((int) y) + 4; }
Object c5(int a) const { std::cout << "c5(a:" << y + a << "): "; return Object(y + 5.1); }
float c6(int a, Object b) const { std::cout << "c6(a:" << y + a << ", b:" << y + b.y << "); "; return ((int) y) + 6.2f; }
};
void f1(void) { std::cout << "f1()" << std::endl; }
void f2(int a) { std::cout << "f2(a:" << a << ")" << std::endl; }
void f3(int a, float b) { std::cout << "f3(a:" << a << ", b:" << b << ")" << std::endl; }
int f4(void) { std::cout << "f4(): "; return 4; }
Object f5(int a) { std::cout << "f5(a:" << a << "): "; return Object(5.1); }
float f6(int a, Object b) { std::cout << "f6(a:" << a << ", b:" << b.y << "); "; return 6.2f; }
Here is the usage example for all of the above functions
int main()
{
std::cout << "=== Global functions" << std::endl;
EventHandler ef1(f1); ef1();
EventHandler ef2(f2); ef2(2);
EventHandler ef3(f3); ef3(3, 3.1f);
EventHandler ef4(f4); std::cout << ef4() << std::endl;
EventHandler ef5(f5); std::cout << ef5(5).y << std::endl;
EventHandler ef6(f6); std::cout << ef6(6, Object(6.1)) << std::endl;
std::cout << std::endl;
std::cout << "=== Member static functions" << std::endl;
EventHandler es1(Object::s1); es1();
EventHandler es2(Object::s2); es2(2);
EventHandler es3(Object::s3); es3(3, 3.1f);
EventHandler es4(Object::s4); std::cout << es4() << std::endl;
EventHandler es5(Object::s5); std::cout << es5(5).y << std::endl;
EventHandler es6(Object::s6); std::cout << es6(6, Object(6.1)) << std::endl;
std::cout << std::endl;
std::cout << "=== Member functions" << std::endl;
Object object(20);
EventHandler em1(&object, &Object::m1); em1();
EventHandler em2(&object, &Object::m2); em2(2);
EventHandler em3(&object, &Object::m3); em3(3, 3.1f);
EventHandler em4(&object, &Object::m4); std::cout << em4() << std::endl;
EventHandler em5(&object, &Object::m5); std::cout << em5(5).y << std::endl;
EventHandler em6(&object, &Object::m6); std::cout << em6(6, Object(6.1)) << std::endl;
std::cout << std::endl;
std::cout << "=== Member const functions" << std::endl;
const Object constObject(30);
EventHandler ec1(&constObject, &Object::c1); ec1();
EventHandler ec2(&constObject, &Object::c2); ec2(2);
EventHandler ec3(&constObject, &Object::c3); ec3(3, 3.1f);
EventHandler ec4(&constObject, &Object::c4); std::cout << ec4() << std::endl;
EventHandler ec5(&constObject, &Object::c5); std::cout << ec5(5).y << std::endl;
EventHandler ec6(&constObject, &Object::c6); std::cout << ec6(6, Object(6.1)) << std::endl;
system("pause");
return 0;
}
Finally - to the point - here an example that shows how much easier in use is the EventHandler I prepared when compared to std::function interface. And actually the reason of such approach.
EventHandler<float, int, Object> example;
example = f6;
example(7, Object(7.1));
example = EventHandler(&object, &Object::m6);;
example(8, Object(8.1));
It’s undefined behavior to call a function through a function pointer(-to-member) of a different type. (Some practical reasons for this rule are that the object’s address might need to be adjusted to call a member function of a base class or that a vtable might be involved.) You can use type erasure to allow calling member functions on objects of different types (which is what std::bind does), or you can (restrict to member functions and) add the class type as a template parameter.
Of course, the usual answer is to just use std::function with a lambda that captures the object in question and calls whatever member function. You can also take the C approach and define various functions with a void* parameter that cast that parameter to a known class type and call the desired member function.
I am attempting to figure out how to move (or just copy if a move is not available) variadic parameters into a lambda within a templated function.
I am testing this with a move-only class (see below) because this would be the "worst-case" that needs to work with my template.
class MoveOnlyTest {
public:
MoveOnlyTest(int a, int b = 20, int c = 30) : _a(a), _b(b), _c(c) {
std::cout << "MoveOnlyTest: Constructor" << std::endl;
}
~MoveOnlyTest() {
std::cout << "MoveOnlyTest: Destructor" << std::endl;
}
MoveOnlyTest(const MoveOnlyTest& other) = delete;
MoveOnlyTest(MoveOnlyTest&& other) :
_a(std::move(other._a)),
_b(std::move(other._b)),
_c(std::move(other._c))
{
std::cout << "MoveOnlyTest: Move Constructor" << std::endl;
other._a = 0;
other._b = 0;
other._c = 0;
}
MoveOnlyTest& operator=(const MoveOnlyTest& other) = delete;
MoveOnlyTest& operator=(MoveOnlyTest&& other) {
if (this != &other) {
_a = std::move(other._a);
_b = std::move(other._b);
_c = std::move(other._c);
other._a = 0;
other._b = 0;
other._c = 0;
std::cout << "MoveOnlyTest: Move Assignment Operator" << std::endl;
}
return *this;
}
friend std::ostream& operator<<(std::ostream& os, const MoveOnlyTest& v) {
os << "{a=" << v._a << "}";
return os;
}
private:
int _a;
int _b;
int _c;
};
And here is the test code I am attempting to get working:
void test6() {
std::cout << "--------------------" << std::endl;
std::cout << " TEST 6 " << std::endl;
std::cout << "--------------------" << std::endl;
MoveOnlyTest v(1, 2, 3);
test6_A(std::move(v));
}
void test6_A(MoveOnlyTest v) {
std::cout << "test6_A()" << std::endl;
test6_B(test6_C, v);
}
template <typename ... ARGSF, typename ... ARGS>
void test6_B(void(*fn)(ARGSF...), ARGS&&... args) {
std::cout << "test6_B()" << std::endl;
//What do I need to get args to be moved/copied into the lambda
auto lambda = [fn, args = ???]() mutable {
(*fn)( std::forward<ARGS>(args)... );
};
lambda();
}
void test6_C(MoveOnlyTest v) {
std::cout << "test6_C()" << std::endl;
std::cout << "v = " << v << std::endl;
}
I am trying to have the exact same behavior as below, only using a generic template so that I can create a lambda which captures and arguments, and calls any function with those arguments.
void test5() {
std::cout << "--------------------" << std::endl;
std::cout << " TEST 5 " << std::endl;
std::cout << "--------------------" << std::endl;
MoveOnlyTest v(1, 2, 3);
test5_A(std::move(v));
}
void test5_A(MoveOnlyTest v) {
std::cout << "test5_A()" << std::endl;
auto lambda = [v = std::move(v)]() mutable {
test5_B(std::move(v));
};
lambda();
}
void test5_B(MoveOnlyTest v) {
std::cout << "test5_B()" << std::endl;
std::cout << "v = " << v << std::endl;
}
To be clear, I don't want to perfectly capture the arguments as in c++ lambdas how to capture variadic parameter pack from the upper scope I want to move them if possible and, if not, copy them (the reason being is that I plan to store this lambda for later execution thus the variables in the stack will no longer be around if they are just captured by reference).
To be clear, I don't want to perfectly capture the arguments as in c++
lambdas how to capture variadic parameter pack from the upper scope I
want to move them if possible
Just using the same form:
auto lambda = [fn, ...args = std::move(args)]() mutable {
(*fn)(std::move(args)...);
};
In C++17, you could do:
auto lambda = [fn, args = std::tuple(std::move(args)...)]() mutable {
std::apply([fn](auto&&... args) { (*fn)( std::move(args)...); },
std::move(args));
};
This question already has answers here:
What is object slicing?
(18 answers)
Closed 1 year ago.
I am building up a CRTP interface and noticed some undefined behavior. So, I built up some sample code to narrow down the problem.
#include <iostream>
template <typename T>
class Base {
public:
int a() const { return static_cast<T const&>(*this).a_IMPL(); }
int b() const { return static_cast<T const&>(*this).b_IMPL(); }
int c() const { return static_cast<T const&>(*this).c_IMPL(); }
};
class A : public Base<A> {
public:
A(int a, int b, int c) : _a(a), _b(b), _c(c) {}
int a_IMPL() const { return _a; }
int b_IMPL() const { return _b; }
int c_IMPL() const { return _c; }
private:
int _a;
int _b;
int _c;
};
template <typename T>
void foo(const T& v) {
std::cout << "foo()" << std::endl;
std::cout << "a() = " << static_cast<Base<T>>(v).a() << std::endl;
std::cout << "b() = " << static_cast<Base<T>>(v).b() << std::endl;
std::cout << "c() = " << static_cast<Base<T>>(v).c() << std::endl;
}
int main() {
A v(10, 20, 30);
std::cout << "a() = " << v.a() << std::endl;
std::cout << "b() = " << v.b() << std::endl;
std::cout << "c() = " << v.c() << std::endl;
foo(v);
return 0;
}
The output of this code is:
a() = 10
b() = 20
c() = 30
foo()
a() = 134217855
b() = 0
c() = -917692416
It appears that there is some problem when casting the child class, which implements the CRTP "interface", to the interface itself. This doesn't make sense to me because the class A plainly inherits from Base so, shouldn't I be able to cast an instance of A into Base?
Thanks!
You copy and slice when you cast to Base<T>.
Cast to a const Base<T>& instead:
std::cout << "a() = " << static_cast<const Base<T>&>(v).a() << std::endl;
std::cout << "b() = " << static_cast<const Base<T>&>(v).b() << std::endl;
std::cout << "c() = " << static_cast<const Base<T>&>(v).c() << std::endl;
It turns out I was casting incorrectly to a value rather than a reference
std::cout << "a() = " << static_cast<Base<T>>(v).a() << std::endl;
should become
std::cout << "a() = " << static_cast<const Base<T>&>(v).a() << std::endl;
If a class has a const reference data member that happens to change outside the scope of such class, is this undefined behaviour?
As an example, let's consider the following C++ code:
#include <iostream>
class A {
int x;
public:
A(int x): x(x){}
void change(int y){
x = y;
}
friend std::ostream & operator << (std::ostream & os, const A & a){
os << a.x;
return os;
}
};
class B {
const A & a;
public:
B(const A & a) : a(a) {}
friend std::ostream & operator << (std::ostream & os, const B & b){
os << b.a;
return os;
}
};
int main(){
A a(1);
B b(a);
std::cout << a << std::endl;
std::cout << b << std::endl;
a.change(2);
std::cout << a << std::endl;
std::cout << b << std::endl;
}
My compiler was able to execute it correctly and the debugger indicated that the x of B::a was changed.
Thank you for you help!
It is not undefined behavior. The const reference that is a member of B only means that an instance of B may not change it via that reference. Because it is a reference, however, something else may change it -- including other members of B that have their own non-const reference to the same instance of A.
Compare the addition of the member c to your existing B class, and note that we are changing it successfully within B::changeA() via the non-const reference and also from C::change() down in main():
#include <iostream>
class A {
int x;
public:
A(int x): x(x){}
void change(int y){
x = y;
}
friend std::ostream & operator << (std::ostream & os, const A & a){
os << a.x;
return os;
}
};
class C
{
A& a;
public:
C(A& a) : a{a} {}
void change(int y) { a.change(y); }
};
class B {
const A & a;
C& c;
public:
B(const A & a, C& c) : a(a), c{c} {}
friend std::ostream & operator << (std::ostream & os, const B & b){
os << b.a;
return os;
}
void changeA(int y) { c.change(y); }
};
int main(){
A a(1);
C c(a);
B b(a,c);
std::cout << a << ' ' << b << '\n';
a.change(2);
std::cout << a << ' ' << b << '\n';
b.changeA(3);
std::cout << a << ' ' << b << '\n';
c.change(4);
std::cout << a << ' ' << b << '\n';
}
See it run live on Coliru, which prints:
1 1
2 2
3 3
4 4
You may not change an object using a constant reference to it but you may change the object itself if it is not constant or using a non-constant reference to the object.
Consider the following demonstrative program.
#include <iostream>
int main()
{
int x = 10;
int &rx = x;
const int &crx = x;
std::cout << "rx = " << rx << '\n';
std::cout << "crx = " << crx << '\n';
rx = 20;
std::cout << "rx = " << rx << '\n';
std::cout << "crx = " << crx << '\n';
return 0;
}
Its output is
rx = 10
crx = 10
rx = 20
crx = 20
It is the same as using a pointer to constant data. For example
#include <iostream>
int main()
{
int x = 10;
int *px = &x;
const int *cpx = &x;
std::cout << "*px = " << *px << '\n';
std::cout << "*cpx = " << *cpx << '\n';
*px = 20;
std::cout << "*px = " << *px << '\n';
std::cout << "*cpx = " << *cpx << '\n';
return 0;
}
I am using the following classes in my code
class pos2d
{
float x, y;
public:
float getx() const;
float gety() const;
//int getz() const; //How to avoid??
};
class pos3d
{
float x, y, z;
public:
float getx() const;
float gety() const;
float getz() const;
};
template<class T, class P>
class entity
{
T type;
P position;
public:
void print() const;
};
My print function in class entity is as follows
template<class T, class P>
void entity<T, P>::print() const
{
if (type == 1 || type == 'A')
cout << "Object is of type " << type << " and has coordinates as (" << position.getx() << ", " << position.gety() << ", " << position.getz() << ")\n\n"; //Avoid getz in pos2d
else if (type == 2 || type == 'B')
cout << "Object is of type " << type << " and has coordinates as (" << position.getx() << ", " << position.gety() << ")\n\n";
}
Note, Type value changes depending of whether class is pos2d or pos2d.
During compilation I get the following error:
Error C2039 'getz': is not a member of 'pos2d' Project1
I am aware that using a common get() function would solve this but i wish to be able to use getz() in my code without having it as part of another common function.
The problem is if you pass pos2d as template parameter the line
cout << "Object is of type " << type << " and has coordinates as (" << position.getx() << ", " << position.gety() << ", " << position.getz() << ")\n\n";
is still instantiated (if is done at runtime), the function cannot be resolved.
The usual way is to use specializations (Type parameter can be omitted):
template<class P>
class entity
{
P position;
public:
void print() const;
};
template<>
void entity<pos3d>::print() const
{
cout << "Object is of type pos3d and has coordinates as ("
<< position.getx() << ", " << position.gety() << ", " << position.getz() << ")\n\n";
}
template<>
void entity<pos2d>::print() const
{
cout << "Object is of type pos2d and has coordinates as ("
<< position.getx() << ", " << position.gety() << ")\n\n";
}
I see 2 simple ways to implement this:
- Make print() a member function of posX class.
- Specialize print() function in entity class.
#include <iostream>
class pos2d
{
float x, y;
public:
float getx() const { return x; }
float gety() const { return y; }
void print() const
{
std::cout << "Object is of type and has coordinates as (" << getx() << ", " << gety() << ")\n\n";
}
};
class pos3d
{
float x, y, z;
public:
float getx() const { return x; }
float gety() const { return y; }
float getz() const { return z; }
void print() const
{
std::cout << "Object is of type and has coordinates as (" << getx() << ", " << gety() << ", " << getz() << ")\n\n";
}
};
template <class P>
class entity
{
P position;
public:
void print() const { position.print(); }
void print_specialized() const;
};
template <>
void entity<pos3d>::print_specialized() const {
std::cout << "Object is of type and has coordinates as (" << position.getx() << ", " << position.gety() << ", " << position.getz() << ")\n\n";
}
template <>
void entity<pos2d>::print_specialized() const {
std::cout << "Object is of type and has coordinates as (" << position.getx() << ", " << position.gety() << ")\n\n";
}
int main() {
entity<pos2d> e;
e.print();
e.print_specialized();
entity<pos3d> e2;
e2.print();
e2.print_specialized();
return 0;
}