I have the following boost::variant type
using MyType = boost::variant<int, double, char, std::string, bool>;
and I would like to be able to use this type in as natural way as possible, in particular I'd like to be able to use the comparison operators such that comparison of types that would compile, give then correct result, otherwise behaviour is undefined (or an exception is thrown). For example suppose I have
MyType x {2}; // int
MyType y {1.0}; // double
MyType z {"hello"}; // std::string
I'd like to be able to compare x with y in the same way as comparing int {2} and double {1.0}. boost::variant already defined operator< etc, so I can make this comparison, but the result is not as expected.
cout << (x < y) << endl; // 1
cout << (y < x) << endl; // 0
I can define the desired behaviour using a boost::static_visitor
template <typename T, typename U, typename R = MyType>
using enable_if_both_arithmetic = std::enable_if_t<std::is_arithmetic<T>::value && std::is_arithmetic<U>::value, R>;
template <typename T, typename U, typename R = MyType>
using enable_if_not_both_arithmetic = std::enable_if_t<!(std::is_arithmetic<T>::value && std::is_arithmetic<U>::value), R>;
class is_less_than : public boost::static_visitor<bool>
{
public:
template <typename T>
bool operator()(const T& lhs, const T& rhs) const
{
return lhs < rhs;
}
template <typename T, typename U>
enable_if_both_arithmetic<T, U, bool> operator()(const T& lhs, const U& rhs) const
{
return lhs < rhs;
}
template <typename T, typename U>
enable_if_not_both_arithmetic<T, U, bool> operator()(const T& lhs, const U& rhs) const
{
return false; // or could throw
}
};
Which can be used like
cout << boost::apply_visitor(is_less_than(), x, y) << endl; // 0
but this is long and ugly. Is there someway I can 'overwrite' the boost::variant::operator< and use my own?
bool operator<(const VcfType& lhs, const VcfType& rhs)
{
return boost::apply_visitor(is_less_than(), lhs, rhs);
}
You are allowed to define a subclass containing the operator< you need, either of the boost::variant<int, double, char, std::string, bool> template instantiation (probably simpler) or of the boost::variant<> template (if you have other cases to cover).
Related
#include <tuple>
#include <utility>
template<typename T>
struct is_tuple_like : std::false_type {};
template<typename... Ts>
struct is_tuple_like<std::tuple<Ts...>> : std::true_type {};
template<typename T, typename U>
struct is_tuple_like<std::pair<T, U>> : std::true_type {};
template<typename T>
concept tuple_like = is_tuple_like<T>::value;
template<tuple_like L, tuple_like R, int N = std::tuple_size_v<L>>
auto operator*(const L &lhs, const R &rhs) { return 0; }
enum { Enum };
int main()
{
Enum * Enum; // causes compilation error
return 0;
}
You can run the code here: http://coliru.stacked-crooked.com/a/f65e333060f40e60
I have defined a concept so-called tuple_like and overloaded operator*() using the concept.
Then, If I multiply enums, my overloaded operator*() for tuple_like is picked up and the compiler complains missing std::tuple_size for enum.
What did I do wrong here and how can I fix it without overload for each class templates - std::tuple and std::pair?
FYI, even if it's unusual, I cannot remove the part of multiplying enums because it's not my code.
Turn tuple_size_v into tuple_size::value to enable SFINAE
template<tuple_like L, tuple_like R, int N = std::tuple_size<L>::value>
auto operator*(const L &lhs, const R &rhs) { return 0; }
However, I don't see any value in declaring an extra template parameter N here. The type that satisfies tuple_like already guarantees that tuple_size_v is a valid value.
It would be more appropriate to move N into the function body
template<tuple_like L, tuple_like R>
auto operator*(const L &lhs, const R &rhs) {
constexpr auto N = std::tuple_size_v<L>; // guaranteed to work
// uses N below
}
Looks like gcc can't handle SFINAE for default values of template arguments. This workaround fixes it:
template<tuple_like L, tuple_like R, int N>
auto operator*(const L &lhs, const R &rhs) { return 0; }
template<tuple_like L, tuple_like R>
auto operator*(const L &lhs, const R &rhs) { return operator*<L, R, std::tuple_size_v<L>>(lhs, rhs); }
I have encountered this greater<pair<int,int>> in many codes.
For example, in the initialisation of the priority queue [code below]
priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq;
I tried a lot of googling but still couldn't find the best answer.
This is the std::greater type.
This is a function object type that does comparisons using the > operator. A rough implementation looks like this:
template<typename T>
struct greater {
constexpr auto operator()(T const& a, T const& b) const -> bool {
return a > b; // greater operator
}
};
In your example, this is being used to order the std::pairs in the priority_queue from "smallest" to "largest" using std::pair's operator >.
The std::greater is a template function object defined as:
template<typename T> struct greater {
constexpr bool operator()(T const& a, T const& b) const {
return a > b; // greater operator
}
};
Now, the '>' operator is defined for std::pair as -
template <class T1, class T2>
bool operator> (const pair<T1,T2>& lhs, const pair<T1,T2>& rhs) { return rhs<lhs; }
Now, the '<' operator is defined as-
template <class T1, class T2>
bool operator< (const pair<T1,T2>& lhs, const pair<T1,T2>& rhs)
{ return lhs.first<rhs.first || (!(rhs.first<lhs.first) && lhs.second<rhs.second); }
So, effectively, the function greater<pair<int, int>> works as-
template<typename T> struct greater {
constexpr bool operator()(T const& a, T const& b) const {
return a.first>b.first || ( (a.first<b.first) && (a.second>b.second));
}
};
That is, greater<pair<int, int>>(a, b) returns true if and only if the 'first' parameter of a is greater than b or if 'first' parameters are equal then 'second' parameter of a is greater than b.
This is a strict weak ordering.
I'm developing a header-only library for automatic/algorithmic differentiation. The goal is to be able to simply change the type of the variables being fed to a function and calculate first and second derivatives. For this, I've created a template class that allows the programmer to select the storage type for the private data members. Included is a snippet below with an offending operator overload.
template <typename storage_t>
class HyperDual
{
template <typename T> friend class HyperDual;
public:
template <typename T>
HyperDual<storage_t> operator+(const HyperDual<T>& rhs) const
{
HyperDual<storage_t> sum;
for (size_t i = 0; i < this->values.size(); i++)
sum.values[i] = this->values[i] + rhs.values[i];
return sum;
}
protected:
std::vector<storage_t> values;
};
Later on, to maximize the versatility, I provide template functions to allow interaction.
template <typename storage_t, typename T>
HyperDual<storage_t> operator+(const HyperDual<storage_t>& lhs, const T& rhs)
{
static_assert(std::is_arithmetic<T>::value && !(std::is_same<T, char>::value), "RHS must be numeric");
return HyperDual<storage_t>(lhs.values[0] + rhs);
}
template <typename storage_t, typename T>
HyperDual<storage_t> operator+(const T& lhs, const HyperDual<storage_t>& rhs)
{
static_assert(std::is_arithmetic<T>::value && !(std::is_same<T, char>::value), "LHS must be numeric");
return HyperDual<storage_t>(lhs + rhs.values[0]);
}
What I'm encountering is that the compiler is trying to instantiate the second non-member template function.
#include "hyperspace.h"
int main()
{
HyperDual<long double> one(1); // There is an appropriate constructor
HyperDual<double> two(2);
one + two;
return 0;
}
I get the static_assert generated error "LHS must be numeric" for this. How would I resolve the ambiguity?
use enable_if_t to make the non-member template can only be applied in the specific context?
template <typename storage_t, typename T, typename = enable_if_t<std::is_arithmetic<T>::value && !(std::is_same<T, char>::value)>>
HyperDual<storage_t> operator+(const HyperDual<storage_t>& lhs, const T& rhs)
{
static_assert(std::is_arithmetic<T>::value && !(std::is_same<T, char>::value), "RHS must be numeric");
return HyperDual<storage_t>(lhs.values[0] + rhs);
}
the static_assert may be duplicated here.
Ok. I found my own issue. It comes down to the difference between static_assert and std::enable_if
Replacing my template declaration and removing static_assert, I achieve equivalent functionality:
template <typename storage_t, typename T,
typename = typename std::enable_if<std::is_arithmetic<T>::value && !std::is_same<T, char>::value>::type>
HyperDual<storage_t> operator+(const T& lhs, const HyperDual<storage_t>& rhs)
{
return HyperDual<storage_t>(lhs + rhs.value());
}
(Small detail, but rhs.values[0] was replaced with rhs.value(). This had nothing to do with the template issue, but was related to member access.
I want to create a shared_ptr content-comparison functor to stand in for std::less<T> in associative containers and std algorithms. I've seen several examples of custom comparators that use the following (or similar) model:
template <typename T>
struct SharedPtrContentsLess {
bool operator()(const boost::shared_ptr<T>& lhs,
const boost::shared_ptr<T> rhs) const {
return std::less<T>(*lhs, *rhs);
//or: return (*lhs) < (*rhs);
}
//defining these here instead of using std::binary_functor (C++11 deprecated)
typedef boost::shared_ptr<T> first_argument_type;
typedef boost::shared_ptr<T> second_argument_type;
typedef bool return_type;
};
But why wouldn't I want to instead extend std::less? Like so:
template <typename T>
struct SharedPtrContentsLess : public std::less< boost:shared_ptr<T> > {
bool operator()(const boost::shared_ptr<T>& lhs,
const boost::shared_ptr<T> rhs) const {
return std::less<T>(*lhs, *rhs);
}
};
Does this buy me anything at all?
I would think this gets me the typedefs for free, as though I was extending the deprecated std::binary_function. In C++03, I actually would be extending it through std::less. However, this would also be portable from C++03 to C++11/14 and even C++17 when std::binary_function will be removed, as it just follows the changes in std::less.
I've read a bunch of answers on StackOverflow regarding std::less use, custom comparison functors, and even some of the Standard specs and proposals. I see specializations of std::less and guidance not to extend STL containers, but I can't seem to find any examples of extending std::less or guidance against it. Am I missing an obvious reason not to do this?
EDIT: Removed C++11 tag, as it is causing confusion to the answerers. I am hoping to get forward-portability, but C++03 is required. If you provide a C++11-only answer for others to use (totally fine), please note that.
You can create a reusable template towards any dereferencable object (i.e. any (smart) pointer) by simply forwarding the call to std::less or any other comparable object.
// c++11
template<template<class> Op, class T> struct deref_mixin;
template<template<class> Op, class T>
struct deref_mixin {
auto operator()(const T &l, const T &r) const
-> decltype(std::declval<Op<T>>()(*l, *r)) {
return Op<T>{}(*l, *r);
}
};
template<template<class> Op>
struct deref_mixin<Op, void> {
template<class T, class U>
auto operator()(const T &l, const U &r) const
-> decltype(std::declval<Op<T>>()(*l, *r)) {
return Op<void>{}(*l, *r);
}
};
template<class T> using less_deref = deref_mixin<std::less, T>;
template<class T> using greater_deref = deref_mixin<std::greater, T>;
template<class T> using my_comparator_deref = deref_mixin<my_comparator, T>;
// c++03
template<template<class> Op, class T>
struct deref_mixin {
bool operator()(const T &l, const T &r) const {
Op<T> op;
return op(*l, *r);
}
};
// Technically, the void template partial specialization isn't defined in c++03, but it should have been :)
template<template<class> Op>
struct deref_mixin<Op, void> {
template<class T, class U>
bool operator()(const T &l, const U &r) const {
Op<void> op;
return op(*l, *r);
}
};
template<class T> struct less_deref : deref_mixin<std::less, T> {};
As you said in your question if you inherit from std::less the you would get the three typedefs that are in std::less. What I like most about inheriting from it is it describes your intent. When I see
struct some_non_specific_name : std::less<some_type>
I know right there that this is a functor that is going to behave as an < for some_type. I don't have to read the struct body to find out anything.
As far as I can see, you are not missing any disadvantage. As you mentioned, you would automatically get the typedefs. The operator< has to be defined in both cases, and there is no difference in its implementation.
There is one thing that you might get that you might find neat, bad or just not applicable to your usecase (from here and here): there is a specialization of std::less for std::less<void> that has a template operator< deduces the return type of the operator< for the given arguments.
Unless you intend to use a SharedPtrContentsLess<void> (which probably doesn't make sense at all), both solutions would be equivalent.
I'd write a deref_less. First, my_less that smartly calls std::less:
struct my_less {
template<class Lhs, class Rhs,
class R = std::result_of_t< std::less<>( Lhs const&, Rhs const& ) >
// class R = decltype( std::declval<Lhs const&>() < std::declval<Rhs const&>() )
>
R operator()(Lhs const&lhs, Rhs const&rhs)const{
return std::less<>{}(lhs, rhs); // or lhs<rhs
}
// exact same type uses `std::less<T>`:
template<class T,
class R = std::result_of_t< std::less<>( T const&, T const& ) >
>
R operator()(T const& lhs, T const& rhs)const{
return std::less<T>{}(lhs, rhs);
}
template<class Lhs, class Rhs,
std::enable_if_t< std::is_base_of<Lhs, Rhs>{} && !std::is_same<Lhs, Rhs>{} >* = nullptr
>
bool operator()(Lhs const* lhs, Rhs const* rhs)const{
return std::less<Lhs const*>{}(lhs, rhs);
}
template<class Lhs, class Rhs,
std::enable_if_t< std::is_base_of<Rhs, Lhs>{} && !std::is_same<Lhs, Rhs>{} >* = nullptr
>
bool operator()(Lhs const* lhs, Rhs const* rhs)const{
return std::less<Rhs const*>{}(lhs, rhs);
}
template<class Lhs, class Rhs,
std::enable_if_t<
!std::is_base_of<Rhs, Lhs>{}
&& !std::is_base_of<Lhs, Rhs>{}
&& !std::is_same<Lhs, Rhs>{}
>* = nullptr
>
bool operator()(Lhs const* lhs, Rhs const* rhs)const = delete;
};
then, a deref_less that does a * then calls myless:
struct deref_less {
template<class Lhs, class Rhs,
class R = std::result_of_t< my_less( decltype(*std::declval<Lhs>()), decltype(*std::declval<Rhs>()) ) >
>
R operator()(Lhs const& lhs, Rhs const&rhs)const {
return my_less{}( *lhs, *rhs );
}
};
in C++14, but everything I used is easy to replace (std::less<> can be replaced with decltype and <s for example).
Because std::less lacks a virtual destructor (i.e. implicit destructor only), inheriting from it could technically lead to undefined behavior. Since neither type contains any data members, destruction should work no matter how the object is referenced, but the standard forbids polymorphic deletion through static destructors because it presents a strong possibility of problems (slicing, incomplete deletion) in most cases.
See this answer:
Thou shalt not inherit from std::vector
I am in the process of converting a large set of geospatial code from one projection to another. To enforce proper units during this conversion, I have introduced Distance, Point, Rectangle, and Polygon templates which take a tag indicating what coordinate system is used. This is working out fairly well, but there are a lot of places where checks are performed for non-zero (!= 0) or positive values (> 0). I would like to be able to overload these operators to allow comparing against 0 without comparing against any other number. Is it possible to accomplish this?
As an additional restriction, I cannot use constexpr because I must support VS 2013, but I'd still be interested to hear if there is a way to do this with constexpr
Just for reference, I am working with something like this:
template<typename Tag> struct Distance
{
int value;
};
template<typename Tag> struct Point
{
Distance<Tag> x;
Distance<Tag> y;
};
// This works fine for comparing two Distances
template<typename Tag> bool operator>(const Distance<Tag>& a, const Distance<Tag>& b) {return a.value > b.value;}
// But I don't want this to allow a > 14, only a > 0
template<typename Tag> bool operator>(const Distance<Tag>& a, int b) {return a.value > b;}
struct Mercator;
typedef Point<Mercator> MercPoint;
struct GuiScale;
typedef Point<GuiScale> GuiPoint;
// etc.
You may use nullptr_t as a hack (as literal 0 convert to nullptr):
template<typename Tag> bool operator>(const Distance<Tag>& a, std::nullptr_t b) {return a.value > 0;}
You might use the conversion-to-any-pointer of a literal zero:
#include <type_traits>
template<typename Tag>
struct Distance
{
private:
using literal_zero = void(Distance::*)();
template<typename U>
using enable_nullptr = typename std::enable_if<
std::is_same< typename std::decay< U >::type, std::nullptr_t >::value
>::type;
public:
int value;
bool operator<( literal_zero ) const { return value < 0; }
template<typename U>
enable_nullptr<U> operator<( const U& ) const = delete;
};
int main() {
Distance<int> a;
a.value = 0;
a < 0;
// a < 42; // does not compile
// a < nullptr; // does not compile
}
This, unlike the other answer, also disallows a < nullptr. Also, if you remove the nullptr-related part and replace the using literal_zero = ... with a typedef, the same technique works with C++98.
Live example
If it's semantically valid to compare with a literal 0, it's valid to allow a conversion from literal 0 as well. With the conversion in place, you need no special case comparisons (Live at Coliru):
template<typename Tag> struct Distance
{
int value;
Distance() = default;
explicit constexpr Distance(int v) : value(v) {}
constexpr Distance(std::nullptr_t) : value(0) {}
friend constexpr bool operator == (const Distance& lhs, const Distance& rhs) {
return lhs.value == rhs.value;
}
friend constexpr bool operator < (const Distance& lhs, const Distance& rhs) {
return lhs.value < rhs.value;
}
// ...
};