Supposed I have a class like this:
template<class T>
class Vector2 {
public:
Vector2(const T a, const T b) : x(a), x(b) {}
T x;
T y;
}
I want to be able to do something like this:
const Vector2<double> d(31.4, 48.2); // note the const!!!
Vector2<int> i = static_cast<Vector2<int>>(d);
// i.x == 31
// i.y == 48
I have tried overloading a generic operator but it seems to break when trying to convert from a const value. Help?
Provide an additional constructor that's taking another template parameter U:
template<class T>
class Vector2 {
public:
template <class U>
Vector2(const Vector2<U> & other) : x(other.x), y(other.y){}
// other code ommited
};
After all, you're trying to use Vector2<T>::Vector2(const Vector2<U> &), where U = double and T = int.
Note that this has nothing to do with your original vector being const. Instead, you're trying to construct a value of type Vector2<int> with a value of another type Value2<double>. Those are distinct types, and therefore you need to provide a constructor.
A possibility would be to write a cast operator which does what you want:
template<class T>
class Vector2 {
public:
Vector2(const T a, const T b) : x(a), y(b) {}
T x;
T y;
template<typename U>
operator Vector2<U>() const { return Vector2<U>( (U)x, (U)y ); }
// ^^^^^^^^ cast operator
};
int main()
{
const Vector2<double> d(31.4, 48.2); // note the const!!!
Vector2<int> i = static_cast<Vector2<int>>(d);
return 0;
}
An additional constructor as shown in the answer of Zeta is the much more elegant solution.
Related
I hope to create a static bool template function that multiple classes may use. I am using this function as a comparator to sort a vector of points. This is what i've done so far:
class.h
class Point2D
{
protected:
int x;
int y;
public:
int getX();
int getY();
Point2D();
Point2D(int x, int y);
template< typename T>
T sortAscending(T a, T b )
{
return a.getX() < b.getX();
}
static bool sortAscending(Point2D a, Point2D b);
}
Inside main.cpp
// my vector contains objects of Point2D that i wish to
//sort according to the value of x coordinates.
sort(p2Vec.begin(),p2Vec.end(),Point2D::sortAscending);
Gives me error:
error: no matching function for call to
‘sort(std::vector::iterator, std::vector::iterator,
)’
Does anyone know what i am doing wrong?
Use a lambda function here like following :
std::sort(p2Vec.begin(),p2Vec.end(),
[](const Point2D & p1, const Point2D & p2) {
return Point2D::sortAscending( p1, p2);
});
See here
Syntax would be:
std::sort(p2Vec.begin(), p2Vec.end(), &Point2D::sortAscending<Point2D>);
and requires the method to be static.
But better create a struct outside:
struct LessByGetX
{
template <typename T>
bool operator () (const T& lhs, const T& rhs) const
{
return lhs.getX() < rhs.getX();
}
};
and use it:
std::sort(p2Vec.begin(), p2Vec.end(), LessByGetX{});
Alternatively, you might use directly lambda:
std::sort(p2Vec.begin(), p2Vec.end(), [](const T& lhs, const T& rhs)
{
return lhs.getX() < rhs.getX();
});
According to boost documentation - proper usage of boost::operators is to derive from it:
class A : boost::operators<A>
{
public:
bool operator < (const A&) const { return false; }
};
Now, I can use > and <= and >= because all of these operators can be implemented with <, see code snippet from boost:
template <class T, class B = operators_detail::empty_base<T> >
struct less_than_comparable1 : B
{
friend bool operator>(const T& x, const T& y) { return y < x; }
friend bool operator<=(const T& x, const T& y) { return !static_cast<bool>(y < x); }
friend bool operator>=(const T& x, const T& y) { return !static_cast<bool>(x < y); }
};
And finally less_than_comparable1 is one of boost::operators base class.
PROBLEM:
But adding such inheritance is not always convenient. E.g. this inheritance means I have to add constructor(s) to some structs, otherwise all old code, such as A{1} stops compiling:
struct A : boost::operators<A>
{
A() = default;
A(int a, int b = 0) : a(a), b(b) {}
int a;
int b;
};
bool operator < (const A&, const A&);
I tried several ways: inner class, static members of boost::operators<A> but it seems that only inheritance works.
I accept an answer that shows the way how to use boost::operators without inheritance.
I can also accept an answer, that explains why this inheritance is needed.
Ok, let's simplify a little this example, why I need inheritance in this very example below to get operator > from operator <?
template <typename A>
struct GtOperator
{
friend bool operator > (const A& l, const A& r)
{
return r < l;
}
};
struct A : private GtOperator<A>
{
bool operator < (const A&) const
{
return false;
}
};
int main() {
if (A{} > A{})
{
return -1;
}
}
Nothing else seems to work, e.g. this way does not work:
struct A
{
GtOperator<A> dummy;
bool operator < (const A&) const
{
return false;
}
};
Is it possible not to inherit from boost::operators, but still use it?
No, basically. It's intended to be inherited from. The reason it works is because argument-dependent lookup will only look for friend functions and function templates in associated classes ([basic.lookup.argdep]/4) - which are going to be A and A's base classes. If boost::operators<A> isn't a base class of A, its friend functions won't be found by name lookup.
Even with new aggregate initialization rules in C++17, A{1,2} would break because you'd have to write A{{},1,2}.
Your best bet is probably to write a macro that functions as a mixin that effectively accomplishes the same thing. So the ordering ones would be:
#define LESS_THAN_COMPARABLE(T) \
friend bool operator>(const T& x, const T& y) { return y < x; } \
friend bool operator<=(const T& x, const T& y) { return !static_cast<bool>(y < x); } \
friend bool operator>=(const T& x, const T& y) { return !static_cast<bool>(x < y); }
class A
{
public:
bool operator < (const A&) const { return false; }
LESS_THAN_COMPARABLE(A)
};
Yes, that kind of sucks. (Also these could be defined as non-member functions as well, just drop the friend and put the macro invocation outside of the class).
The other alternative, besides adding constructors and writing macros, is to hope that <=> comes to fruition and then wait a few years to be able to use it.
I have a bit of a problem with operator overloading and inheritance in C++.
Quick sketch:
class A {
public:
A operator+ (const A &b) const { ... }
};
class B : public A {
...
};
Now suppose I have two instances of B, x and y. If I add them I will get a thing of type A, however I want it to be of type B.
What is the best way of accomplishing this (aside from reimplementing them in class B) ? CRTP?
You can implement operator+ outside of the class as a template:
template<class type> type operator+(const type& left, const type& right)
{
type toReturn;
toReturn.value = left.value + right.value;
return toReturn;
}
class A {
private:
int value;
template <class type>
friend type operator+<type>(const type& left, const type& right);
};
class B : public A {
};
int main()
{
B test1, test2;
B test3 = test1 + test2;
}
This approach has certain down-sides. The compiler will aggressively try to instantiate the operator+ template for types which you don't want to define operator+, so be aware of that.
I've got this piece of code for a class (this is a snippet):
template<typename T>
class Pos2 {
public:
T x, y;
Pos2() : x(0), y(0) {};
Pos2(T xy) : x(xy), y(xy) {};
Pos2(T x, T y) : x(x), y(y) {};
};
Now, I've also got 2 typedefs for it:
typedef Pos2<pos_scalar> Pos;
typedef Pos2<size_scalar> Size;
Everything works as expected, but when I do this:
Pos p(5.5, 6.5);
Size s(3, 8);
p = s;
I get this error:
error: conversion from ‘Size {aka Pos2<short int>}’ to non-scalar type ‘Pos’ requested
It makes sense, but I'd like to know how to fix it =P
Add a constructor
template <typename Type2> Pos2(const Pos2<Type2> &other)
{ x = other.x; y = other.y; }
You need to define an assignment operator for assignment from type Size to type Pos, because these are not the same type and therefore there is no default assignment operator between the two.
I guess you want to use a template here, so any instantiation of Pos2 can be used to assign to another instantiation. For example like so:
template<typename T>
class Pos2 {
public:
T x, y;
Pos2() : x(0), y(0) {};
Pos2(T xy) : x(xy), y(xy) {};
Pos2(T x, T y) : x(x), y(y) {};
template<typename FromT>
Pos2<T>& operator=(const Pos2<FromT>& from) {
x = from.x;
y = from.y;
return *this;
}
};
You should do the same with the copy constructor (not shown here), because it might likely happen that you want to copy construct in the same scheme at some point.
This does only work if the assignment between type T and FromT, that is pos_scalar and size_scalar is possible. If not try to add correct explicit conversions and/or template specializations for the assignment operator.
Also if any of the members of Pos2 are private/protected you will need to friend the assignment operator or provide adequate getters.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Preventing non-const lvalues from resolving to rvalue reference instead of const lvalue reference
Conflict between copy constructor and forwarding constructor
I have these classes that I need for storing std::unique_ptr (adapted boost::any):
class any
{
public:
any()
: content(0)
{
}
any(any const&) = delete;
any(any && other)
: content(other.content)
{
content = 0;
}
template<typename ValueType>
any(ValueType const& value)
: content(new holder<ValueType>(value))
{
}
template<typename ValueType>
any(ValueType && value,
typename std::enable_if<!std::is_lvalue_reference<ValueType>::value,
void>::type* = 0)
: content(new holder<ValueType>(std::move(value)))
{
}
~any()
{
delete content;
}
public: // modifiers
any & swap(any & rhs)
{
std::swap(content, rhs.content);
return *this;
}
any & operator=(const any &) = delete;
any & operator=(any && rhs)
{
return swap(rhs);
}
template<typename ValueType>
any & operator=(ValueType const& rhs)
{
any(rhs).swap(*this);
return *this;
}
template<typename ValueType>
typename std::enable_if<!std::is_lvalue_reference<ValueType>::value,
any&>::type operator=(ValueType && rhs)
{
any(std::move(rhs)).swap(*this);
return *this;
}
public: // queries
bool empty() const
{
return !content;
}
const std::type_info & type() const
{
return content ? content->type() : typeid(void);
}
private: // types
class placeholder
{
public: // structors
virtual ~placeholder()
{
}
public: // queries
virtual const std::type_info & type() const = 0;
};
template<typename ValueType>
class holder : public placeholder
{
public: // structors
template <class T>
holder(T && value)
: held(std::forward<T>(value))
{
}
holder & operator=(const holder &) = delete;
public: // queries
virtual const std::type_info & type() const
{
return typeid(ValueType);
}
public:
ValueType held;
};
private: // representation
template<typename ValueType>
friend ValueType * any_cast(any *);
template<typename ValueType>
friend ValueType * unsafe_any_cast(any *);
placeholder * content;
};
and this test case:
any a;
any b(a);
b = a;
and this one:
std::map<int, int> map({{1,1},{2,2}});
any b(map);
std::cout << map.size() << std::endl; // displays 0
To my horror, under gdb, I've noticed that the move constructor and the move assignment operator are called when constructing and assigning b (even from map), even though I did not tag a with std::move and it is not a temporary. Can someone explain why?
My first answer was wrong. After reading through your very unreadable code again I see that you have explicitly provided a move and default constructor, but no copy constructor. If a class has any user defined constructor (of which you have two), the compiler will not generate any other constructors for that class. Hence, your class does not have a copy constructor.
Edit: So, back to my original answer (prompted by your comment). §12.8/7 [class.copy] says:
A member function template is never instantiated to perform the copy
of a class object to an object of its class type. [Example:
struct S {
template<typename T> S(T);
template<typename T> S(T&&);
S();
};
S f();
const S g;
void h() {
S a( f() ); // does not instantiate member template;
// uses the implicitly generated move
constructor S a(g); // does not instantiate the member template;
// uses the implicitly generated copy constructor
}
—end example ]
Since your copy contructor is a member-template, but your move constructor is not, the later is chosen here (your case is different from the example in that respect).