Easy way to make std::compare functions unary - c++

I need to use different compare functions as unary functions, where one of the values is embedded inside the comparator. To do so I created an adaptor class, something like:
template<typename T, typename Compare>
class CompareAdaptor : private Compare
{
public:
CompareAdaptor(T value)
: mValue(value)
{
}
bool operator()(T v) const
{
return Compare::operator()(v, mValue);
}
private:
T mValue;
};
and now I can define a new unary comparator like:
template<typename T>
using EqualTo = CompareAdaptor<T, std::equal_to<T>>;
template<typename T>
using LessEqual = CompareAdaptor<T, std::less_equal<T>>;
My questions is: Is there a simpler way(without using the adaptor class) to define those unary comparators? I think this is a very common problem and probably you have better solutions.

In C++11, this is as good as it gets. But I'd rather expect the predicate to be directly constructed at the call site :
std::find_if(begin(v), end(v), [limit](int i) { return i < limit; });
In C++14, you could use return type deduction to make a factory fuction :
template <class Comp>
auto predicate(typename Comp::second_argument_type rhs) {
return [c = Comp{}, rhs](typename Comp::first_argument_type lhs) {
return c(lhs, rhs);
};
}
Example call : predicate<std::less<int>>(4) returns the function object.
Live on Coliru

#Quentins answer can also be made compilable in C++11 using std::function as the return type which the lambdas are convertible to:
template <class Comp>
std::function<typename Comp::result_type (typename Comp::first_argument_type)> predicate(typename Comp::second_argument_type rhs)
{
return [rhs](typename Comp::first_argument_type lhs){
Comp c{};
return c(lhs, rhs);
};
}
live on coliru

Related

Template default init, if there no default constructor in a class

I'm pretty new in C++. I have wrote a function template to sum all elements in a vector like this:
template<typename T>
inline T sumator(const std::vector<T> &sequence) {
T init = T{};
return accumulate(sequence.begin(), sequence.end(), init);
}
All work well until the default constructor is not declare, but declare constructor from, for example, 2 arguments.
Like this:
class A {
private:
int a;
int b;
public:
// A() = default;
A(int aa, int bb) : a(aa),b(bb){};
A operator+(const A &right) const {
return {a + right.a, b + right.b};
}
bool operator==(const A &right) const {
return (a == right.a && b == right.b);
}
};
vector<A> bc = {{3,5},{5,5}};
A res = Adder::sumator(works);
A result = {8,10};
assert(result,res);
Now I get an error like : error: no matching constructor for initialization of 'A'
T init = T{};
How can I avoid this situation, not using https://en.cppreference.com/w/cpp/types/is_default_constructible
UPD: I have many classes, some of them with default constructor, some without but with constructor for 2 arg, some for 3, e.t.c. And I want to accumulate every situation well
Possible solutions that I can think of.
Let users rely on std::accumulate by providing an initial vlaue.
Provide an overload of sumator with an initial value. Users can call the overload with an initial value if they have a type that does not have default constructor.
Insist that the type for which the function is invoked have a default consructor.
template<typename T>
inline T sumator(const std::vector<T> &sequence, T init) {
return accumulate(sequence.begin(), sequence.end(), init);
}
template<typename T>
inline T sumator(const std::vector<T> &sequence) {
return accumulate(sequence.begin(), sequence.end(), {});
}
You can add another parameter with default argument.
template<typename T>
inline T sumator(const std::vector<T> &sequence, const T& init = T{}) {
return accumulate(sequence.begin(), sequence.end(), init);
}
For types could be default-constructed you can still
sumator(some_vector);
And specify the default value when T can't be default-constructed. e.g.
sumator(some_vector, A{0, 0});
You can split it in two overloads and add a static_assert to provide a nice compilation error message if someone tries to use it the wrong way.
One overload would be valid only if the type is default constructible and one overload would be valid for types that is not as well as for those that are:
#include <type_traits>
#include <vector>
template<typename T>
T sumator(const std::vector<T>& sequence) {
static_assert(std::is_default_constructible_v<T>);
return std::accumulate(sequence.begin(), sequence.end(), T{});
}
template<typename T>
T sumator(const std::vector<T>& sequence, const T& init) {
return std::accumulate(sequence.begin(), sequence.end(), init);
}
Another option is to add a default argument that can be used for types that are default constructible - and you could also make it more generic to make it work with not only vectors but with lists etc.
template<template<class, class...> class C, class T, class... Ts>
T sumator(const C<T, Ts...>& sequence, const T& init = T{}) {
return std::accumulate(sequence.begin(), sequence.end(), init);
}

Comparer that takes the wanted attribute

In order to use a standard function like std::sort on some standard container Container<T>
struct T{
int x,y;
};
based on the y value, you need to write something like (for example):
std::vector<T> v;
//fill v
std::sort(v.begin(),v.end(),[](const auto& l,const auto& r){
return l.y<r.y;
});
The comparer that was written as lambda function is used too much and re-written again and again during the code for various classes and attributes.
Considering the case where y's type is comparable (either like int or there is an overload for the < operator), is there any way to achieve something like:
std::sort(v.begin(),v.end(),imaginary::less(T::y)); // Imaginary code
Is it possible in C++ to write such a function like less? or anything similar?
I am asking because I remember something like that in some managed language (I am not sure maybe C# or Java). However, I am not sure even about this information if it is true or not.
template<typename T, typename MT>
struct memberwise_less
{
MT T::* const mptr;
auto operator()(const T& left, const T& right) const
{ return (left.*mptr) < (right.*mptr); }
};
template<typename T, typename MT>
memberwise_less<T, MT> member_less(MT T::*mptr)
{
return { mptr };
}
and then you can do
std::sort(v.begin(), v.end(), member_less(&T::y));

How to allow derived classes in a C++ template argument

I want to write a function that accepts a collection of type T, say std::vector<T>, but that does two different things depending on T. For example, if T is == comparable, then use a == b, else if T has a .value element, use that (a.value == b.value).
My first attempt was to use an overloaded function, but that fails if I pass in a derived class (subclass) of T.
Suppose, for example, I want to create an Exists method. (I know this can be implemented using std::find_if; it is an example only.) The following fails to compile:
using namespace std;
struct Base {
Base(string s) : value(std::move(s)) {}
string value;
};
struct Derived : public Base {
Derived(string s) : Base(std::move(s)) {}
};
bool Exists(const vector<string>& collection, const string& item) {
for (const auto& x : collection)
if (x == item)
return true;
return false;
}
bool Exists(const vector<Base>& collection, const Base& item) {
for (const auto& x : collection)
if (x.value == item.value)
return true;
return false;
}
This works fine for exact matches, such as:
Exists(vector<string>{"a", "b", "c"}, "b");
Exists(vector<Base>{{"a"}, {"b"}, {"c"}}, Base{"b"});
But it fails for derived classes:
Exists(vector<Derived>{{"a"}, {"b"}, {"c"}}, Derived{"b"})
The error is:
foo.cc:35:13: error: no matching function for call to 'Exists'
foo.cc:23:6: note: candidate function not viable: no known conversion from 'vector<Derived>' to 'const vector<Base>' for
1st argument
How can I solve this? I am interested in multiple answers, since each solution probably has pros and cons.
This is probably not a duplicate per se, but very close to this:
Is it possible to write a template to check for a function's existence?
My recommended approach is the more general solution implemented in that answer: use SFINAE.
The snippet of how to test for a member function is below (adapted from here):
template <class T>
class has_value {
template <class M>
static inline bool try_match(decltype(&M::value)) { }
template <class M>
static inline int try_match(...) { }
public:
static constexpr bool value =
sizeof(try_match<T>(nullptr)) == sizeof(bool);
};
this can then be combined with std::enable_if to solve your problem. I have posted a full solution as a GitHub gist.
In my opinion, this is superior to using base and inheritance checks as it works by simply checking (at compile-time) whether a given type has a given member. Additionally, it works for anything that has a type, meaning members, functions, static members / functions, types, etc.
One solution is to template the Exists() method and then have an overloaded comparison function. This only works if the type-specific code can be isolated. For example:
bool Equals(const string& a, const string& b) { return a == b; }
bool Equals(const Base& a, const Base& b) { return a.value == b.value; }
template <typename T>
bool Exists(const vector<T>& collection,
const typename vector<T>::value_type& item) {
for (const auto& x : collection)
if (Equals(x, item))
return true;
return false;
}
Pro: Probably the simplest solution.
Con: Does not work if you need to do some sort of expensive work up front. For example, if you need to call x.SomeExpensiveMethod() and you want to cache it for the item argument, this will not work.
Note that you need to use vector<t>::value_type and not just T in the argument or else you may get an error such as:
foo3.cc:30:13: error: no matching function for call to 'Exists'
cout << Exists(vector<string>{"a", "b", "c"}, "b") << endl;
^~~~~~
foo3.cc:21:6: note: candidate template ignored: deduced conflicting types for parameter 'T' ('std::basic_string<char>' vs.
'char [2]')
One solution is to use std::enable_if and std::is_base_of. For example:
template <typename T>
typename std::enable_if<std::is_base_of<Base, T>::value, bool>::type
Exists(const vector<T>& collection,
const typename vector<T>::value_type& item) {
const auto& item_cached = item.SomeExpensiveFunction();
for (const auto& x : collection)
if (x.SomeExpensiveFunction() == item_cached)
return true;
return false;
}
template <typename T>
typename std::enable_if<!std::is_base_of<Base, T>::value, bool>::type
Exists(const vector<T>& collection,
const typename vector<T>::value_type& item) {
for (const auto& x : collection)
if (x == item)
return true;
return false;
}
Pro: Much more general than overloading the Equals() function as described in another answer. In particular, the entire Exists() method can be customized per type.
Con: Much uglier, more complicated code.

(C++) Template to check whether an object is in a vector/array/list/...?

Is it possible to create a template in C++(11) for a function to check whether an object is contained in either a std::vector, std::array or std::list (and possibly even more container types)?
What I have by now:
typedef std::shared_ptr<Tag> SharedTag;
typedef std::vector<SharedTag> TagList;
bool
Tag::isIn(const TagList& lst) {
return std::any_of(lst.begin(), lst.end(), [this](const SharedTag& t) {
return t->name == this->name;
});
}
Tag is a normal class. The comparison, of course, should be done t == this, which will be an operator== later on. I did not include this here for simplicity.
So, is it possible to write the upper code only once (without the typedef's though,) for std::vector, std::array, std::list(, maybe for std::set) and so on?
I couldn't find a base-type of all these classes,... which would be my first idea...
Option 1 (good): just use std::find directly:
std::vector<int> v; // populate v however you want
std::vector<int>::const_iterator i = std::find(v.cbegin(), v.cend(), 42);
if (i != v.end()) {
// Now you know 42 is in v
} else {
// Now you know 42 is not in v
}
Option 2 (better): wrap std::find in a helper function:
template <typename Container, typename Value>
bool contains(const Container& c, const Value& v)
{
return std::find(std::begin(c), std::end(c), v) != std::begin(c);
}
// Example usage:
std::vector<int> v; // populate v however you want
if (contains(v, 42)) {
// You now know v contains 42
}
Option 3 (best): use the find method of containers that provide one (which is faster for sorted containers, like set), and std::find for containers that don't provide one:
// If you want to know why I added the int and long parameter,
// see this answer here: http://stackoverflow.com/a/9154394/1287251
template <typename Container, typename Value>
inline auto contains(const Container& c, const Value& v, int) -> decltype(c.find(v), bool()) {
return c.find(v) != std::end(c);
}
template <typename Container, typename Value>
inline bool contains(const Container& c, const Value& v, long) {
return std::find(std::begin(c), std::end(c), v) != std::end(c);
}
template <typename Container, typename Value>
bool contains(const Container& c, const Value& v) {
return contains(c, v, 0);
}
// Example usage:
std::set<int> s; // populate s however you want
if (contains(s, 42)) {
// You now know s contains 42
}
Of course, you could write std::find yourself, but you might as well use it.
You may use template:
typedef std::shared_ptr<Tag> SharedTag;
template <typename Container>
bool Tag::isIn(const Container& lst) {
return std::any_of(lst.begin(), lst.end(), [this](const SharedTag& t) {
return t->name == this->name;
});
}
That requires that Container is a container of something convertible to SharedTag.
There is no common base-type between those containers. That's just not the way the STL library works, it is based on templates and generic programming principles.
So, if you want to implement the function once for all containers, you would have to make it a template. Here is a basic form:
template <typename TagContainer>
bool Tag::isIn(const TagContainer& lst) {
return std::any_of(lst.begin(), lst.end(), [this](const SharedTag& t) {
return t->name == this->name;
});
};
But this has the problem that you could technically pass anything to this function that isn't actually a container of SharedTag, so, to solve this issue, you could use a trick called Sfinae to enforce that rule:
template <typename TagContainer>
typename std::enable_if< std::is_same< SharedTag, typename TagContainer::value_type >::value,
bool >::type Tag::isIn(const TagContainer& lst) {
return std::any_of(lst.begin(), lst.end(), [this](const SharedTag& t) {
return t->name == this->name;
});
};
Which kind of ugly, but it works.
There is still one problem though. I suspect that your Tag class is a normal non-template class, which means that you are probably implementing it in a cpp file, but templates need to be implemented in the header file (because function templates need to have their implementation visible to the compiler to generate a new concrete version of it for each type that you call it with).
One way to avoid this problem is to provide a number of overloaded non-template functions for each container you want to support, and then, under-the-hood, you call a local function template, and in this case, you don't need the sfinae trick to constrain it, since it is already limited to the set of overloads that you provided. Something like this:
template <typename TagContainer>
bool Tag::isIn_impl(const TagContainer& lst) {
return std::any_of(lst.begin(), lst.end(), [this](const SharedTag& t) {
return t->name == this->name;
});
};
bool Tag::isIn(const std::list<SharedTag>& lst) {
return isIn_impl(lst);
};
bool Tag::isIn(const std::vector<SharedTag>& lst) {
return isIn_impl(lst);
};
bool Tag::isIn(const std::set<SharedTag>& lst) {
return isIn_impl(lst);
};
Note that the isIn_impl is a member function template that should be declared in the header file, in the private section of the class, and can safely be defined in the cpp file, because that cpp file is the only place where that function template is called from.
The obvious issue with that solution is that you have to manually provide every overload that you want to support, which means that it isn't very "scalable" in the future, but in real-life, there probably aren't that many containers that you'd want to support. If you want the full generality, you really have to use the template approach (unless you want to do type-erasure on the container... but that's a bit beyond the scope of what I'm willing to explain here).
You can use a nested variadic template to achieve this. Here is a handy demo: note the magic part, template <template <typename...> class V, typename E>. A variadic template is necessary because vector, list &co. all have a different number of template parameters (allocator, comparator etc.) for which a default value is supplied by the STL.
#include <vector>
#include <string>
#include <memory>
#include <algorithm>
#include <list>
#include <set>
#include <iostream>
class Tag {
public:
Tag(const std::string &n): name(n) {}
template <template <typename...> class V, typename E>
bool isIn(const V<E> &lst) {
return std::any_of(lst.begin(), lst.end(), [this](const E &t) {
return t.name == this->name;
});
}
private:
std::string name;
};
typedef std::shared_ptr<Tag> SharedTag;
typedef std::vector<SharedTag> TagList;
int main() {
Tag t("foo");
// Set needs some extra bits to work (a `<` operator etc.)
//std::set<Tag> a = {Tag("foo"), Tag("bar")};
std::vector<Tag> b = {Tag("foo"), Tag("bar")};
std::list<Tag> c = {Tag("foo"), Tag("bar")};
//std::cout << t.isIn(a) << std::endl;
std::cout << t.isIn(b) << std::endl;
std::cout << t.isIn(c) << std::endl;
}

C++ operator[] overloading with template accessing boost::variant

I've this class with a map attribute which values are boost::variant.
typedef boost::variant<char, int, bool, unsigned short, float, timeval, double > MultiType;
class A {
public:
template<class T>
T& operator[](const std::string& key) {
return boost::get<T>(map_[key]);
}
template<class T>
std::string keyTypeToString(const std::string& key) {
std::stringstream ss;
ss << boost::get<T>(map_[key]);
return ss.str();
}
private:
std::map<std::string, MultiType> map_;
};
From main:
A a;
a["param"];
Compiler report this errors:
../src/main.cpp:8:25: error: no match for ‘operator[]’ in ‘a["param"]’
../src/main.cpp:8:25: note: candidate is:
../src/util/A.h:53:5: note: template T& A::operator[](const string&)
Maybe I'm missing something trivial, but I can't understand where I'm wrong..
Start with this:
template<class T>
T& get(const std::string& key) {
return boost::get<T>(map_[key]);
}
You call this like a.get<int>("hello"), where it will get the element "hello" as an int.
Next, write this:
struct pseudo_ref {
std::string const& str;
A* a;
template<typename T>
operator T&()&&{
return a->get<T>(str);
}
template<typename T>
pseudo_ref operator=( T&& t ) && {
a->get<typename std::decay<T>::type>(str) = std::forward<T>(t);
return {str, a};
}
pseudo_ref(pseudo_ref const&)=delete;
pseudo_ref& operator=(pseudo_ref const&)=delete;
pseudo_ref( std::string const& s, A* a_ ):str(s), a(a_) {}
};
then back in A:
pseudo_ref operator[](std::string const& str) {
return {str, this};
}
and we get [] that magically converts for you, so long as you assign to it/read from it using the exactly correct type.
This is somewhat dangerous, but cool.
If you want a const pseudo_ref, you need another class to represent it (with no = and operator T const& instead of operator T&).
In practice, this kind of malarkey is rarely worth it.
I wrote this in C++11, because writing it in C++03 is slightly more painful (and runs into lifetime issues with pseudo_ref -- they still exist if you have an auto&& x = a["hello"]), and less pain is good.
class A {
public:
class proxy {
friend class A;
private:
MultiType& it;
proxy(MultiType& it): it(it) {}
public:
template<typename T>
operator T&() {
return boost::get<T>(it);
}
};
proxy operator[](const std::string& key) {
return proxy(map_[key]);
}
private:
std::map<std::string, MultiType> map_;
};
EXPLANATION:
I can see that Yakk was trying similar thing. I have encapsulated the MultiType& from map_[key] in the proxy and then left the work on conversion (type-cast) operator. That's all.
Simple a[""] without assignment gets you the proxy.
double d = a["double"] will try to convert the proxy to double and thus call proxy::operator double&() (I had to test it because I was not sure if the type deduction will work as it is or will need some more work - well, it works!)
AFTERNOTE: It was not clear from the question and code provided what operations are allowed. We can modify the proxy to allow other operations or make it more readonly by changing the signature of type-conversion operator to return const T& instead.
Allowing modification leads to question: why not using MultiType& directly? (returning it from A::operator[]) And that leads to question: why class A at all?
AFTERNOTE #2: boost::variant does not have type-conversion operator and there must have been a reason for it. Think about this code:
int i = a["double"]
Runtime exception! I think that best solution would be to sub-class the MultiType and define type-conversion operator there (while checking boost::variant::which()).
ASSIGNING TO ALREADY PRESENT NAMES:
class A { ...
class proxy { ...
template<class T> proxy& operator=(const T& rhs) {
it = rhs; return *this; }
...but the above can only work if we already have some value in the map.
class A { ...
A() { map_["pi"] = 3.14; } ...
a["pi"] = 3.1415;
COMPLETE REDISIGN:
class MultiType: public boost::variant<int, double, ...> {
public:
template<class T> operator T() {
switch(which()) {
case 0: return boost::get<int>(*this);
case 1: return boost::get<double>(*this);
...
Now we can use std::map<std::string, MultiType> directly (without class A or any proxy).
template<class T>
T& operator[](const std::string& key) {
return boost::get<T>(map_[key]);
}
There's no way for the compiler to deduce T from a call like a["param"];. You'd need to specify it explicitly
a.operator[]<int>("param");
which I doubt is what you're after, but what do I know.