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.
Related
To use a custom type in a std::unordered_set I have to options.
1) Implement the == operator for my type and specialize std::hash
struct MyType {
int x;
bool operator==(const MyType& o) {
return this.x == o.x;
}
};
namespace std
{
template<>
struct hash<MyType> {
size_t operator()(const MyType& o) const {
return hash<int>()(o.x);
}
};
}
std::unordered_set<MyType> mySet;
Or 2), provide functor classes:
struct MyTypeHash {
size_t operator()(const MyType& o) const {
return std::hash<int>()(o.x);
}
};
struct MyTypeCompare {
bool operator()(const MyType& o1, const MyType& o2) const {
return o1.x == o2.x;
}
};
std::unordered_set<MyType, MyTypeHash, MyTypeCompare> mySet;
The second approach lets me choose new behaviour for every new instantion of std::unordered_set, while with the first approach the behaviour as being part of the type itself will always be the same.
Now, if I know that I only ever want a single behaviour (I'll never define two different comparators for MyType), which approach is to be preferred? What other differences exist between those two?
Attaching the behavior to the type allows for code like
template<template<class> Set,class T>
auto organizeWithSet(…);
/* elsewhere */ {
organizeWithSet<std::unordered_set,MyType>(…);
organizeWithSet<std::set,MyType>(…);
}
which obviously cannot pass custom function objects.
That said, it is possible to define
template<class T>
using MyUnorderedSet=std::unordered_set<T, MyTypeHash,MyTypeCompare>;
and use that as a template template argument, although that introduces yet another name and might be considered less readable.
Otherwise, you have to consider that your operator== is simultaneously the default for std::unordered_set and std::find, among others; if the equivalence you want for these purposes varies, you probably want named comparators. On the other hand, if one suffices, C++20 might even let you define it merely with =default.
I want to write a proxy class, that takes a template value and can be compared to any class that the template can be compared to.
template <class T>
class Proxy {
public:
Proxy(T value) : _value(value) {}
template <class U> // this should exist only if the T == U operator is defined
bool operator==(U const& other) const { return _value == other; }
template <class U> // this should exist only if U == T is defined
friend bool operator==(U const& first, Proxy<T> const& second) const { return first == second._value; }
private:
T _value;
};
for example, since this is legal code:
bool compare(std::string first, std::string_view second) {
return first == second;
}
I want this to be legal, too:
bool compare(std::string first, Proxy<std::string_view> second) {
return first == second;
}
but just to clarify, this should work for any classes that can be compared, or can be implicitly converted in order to be compared. Can I define a template conditional that will check for either case?
Since your criteria is essentially whether or not an expression like _value == other is well-formed, you can just rely on expression SFINAE to test it.
template <class U> // this should exist only if the T == U operator is defined
auto operator==(U const& other) const -> decltype(_value == other)
{ return _value == other; }
template <class U, std::enable_if_t<!std::is_same<U, Proxy>::value, int> = 0> // this should exist only if U == T is defined
friend auto operator==(U const& first, Proxy const& second) -> decltype(first == second._value)
{ return first == second._value; }
It may not be very DRY, since we need to repeat the expression twice, but it's a fairly simple way to do SFINAE, which is a major plus.
The other thing to note is that we do not want the second overload to be considered recursively, which may happen upon comparison of two proxies. So we need another SFINAE condition, spelled out the old fashioned way with enable_if, to discard the overload when U is a Proxy. This relies on the C++14 feature whereby substitutions are checked in declaration order. Putting it first prevents the recursion in first == second._value.
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
I have a set of polymorphic classes, such as:
class Apple {};
class Red : public Apple {};
class Green : public Apple {};
And free functions which compare them:
bool operator==(const Apple&, const Apple&);
bool operator< (const Apple&, const Apple&);
I'm designing a copyable wrapper class which will allow me to use classes Red and Green as keys in STL maps while retaining their polymorphic behaviour.
template<typename Cat>
class Copy
{
public:
Copy(const Cat& inCat) : type(inCat.clone()) {}
~Copy() { delete type; }
Cat* operator->() { return type; }
Cat& operator*() { return *type; }
private:
Copy() : type(0) {}
Cat* type;
};
I want the Copy<Apples> type to be as interchangeable with Apples as possible. There are a few more functions I'll have to add to the Copy class above, but for now I'm working on a free function for operator==, as follows:
template<typename Cat>
bool operator==(const Copy<Cat>& copy, const Cat& e) {
return *copy == e;
}
Here is part of my testing code:
Red red;
Copy<Apple> redCopy = red;
Copy<Apple> redCopy2 = redCopy;
assert(redCopy == Red());
But the compiler is telling me
../src/main.cpp:91: error: no match for ‘operator==’ in ‘redCopy == Red()’
How do I get it to recognize my operator== above? I suspect the answer might be in adding some implicit conversion code somewhere but I'm not sure what to do.
Your template is declared as
template <typename Cat>
bool operator==(const Copy<Cat>& copy, const Cat& e)
This doesn't match redCopy == Red() because Red() is of type Red, so the compiler deduces Red as the type of the second argument, i.e. Cat = Red, but then it expects the type of the first argument to be Copy<Red>, which it is not (redCopy's type is Copy<Apple>).
What you really want to express is something like
template <typename Cat>
bool operator==(const Copy<Cat>& copy, const something-that-derives-from-Cat& e)
The easiest way to do this, is to add a second template parameter:
template <typename Cat, typename DerivedFromCat>
bool operator==(const Copy<Cat>& copy, const DerivedFromCat& e)
Of course, this doesn't get the compiler to enforce that DerivedFromCat is actually derived from Cat. If you want this, you can use boost::enable_if:
template <typename Cat, typename DerivedFromCat>
typename enable_if<is_base_of<Cat, DerivedFromCat>, bool>::type
operator==(const Copy<Cat>&, const DerivedFromCat& e)
But that may be a bit of overkill...
But... How do you expect it to work? You declared a template operator
template<typename Cat>
bool operator==(const Copy<Cat>& copy, const Cat& e)
meaning that the type on the RHS is the same as template argument on the LHS (Cat in both cases). Yet you expect it to be called in case of
redCopy == Red()
where redCopy is Copy<Apple>. How?
Note: the template argument for redCopy is Apple, not Red. Your template operator simply can't possibly match these types.
If you had your redCopy declared as
Copy<Red> redCopy;
then your operator would work. Or if you did
redCopy == Apple()
your operator would work as well. But when you mix types like your original
Copy<Apple> redCopy;
redCopy == Red();
it simply can't work. What is your intent in this case?
#HighCommander4 explained what is wrong here. An alternative solution is to disable deduction for the second parameter of operator==. The type of the second parameter is then deduced solely based on the first argument of the ==-operator:
template<typename T> struct identity { typedef T type; };
template<typename Cat>
bool operator==(const Copy<Cat>& copy, typename identity<Cat>::type const& e) {
return *copy == e;
}
If you do it like this, there is no contradiction as to what type Cat is supposed to stand for, and the operator== will work as expected.
I'm building a series of predicates that duplicate lots of code, and so are being changed into a single template function class based on the std::unary_function. The idea is that my class interface requires methods such as Element_t Element() and std::string Name() to be defined, so the predicate template arguments are the object type and a value type to which comparison will be made as follows:
// generic predicate for comparing an attribute of object pointers to a specified test value
template <class U, typename R>
class mem_fun_eq : public std::unary_function <U*, bool> {
private:
typedef R (U::*fn_t)();
fn_t fn;
R val;
public:
explicit mem_fun_eq (fn_t f, R& r) : fn(f), val(r) { }
bool operator() (U * u) const {
return (u->*fn)() == val;
}
};
Thus, if I have:
class Atom {
public:
const Element_t& Element() const { return _element; }
const std::string& Name() const { return _name; }
};
I would like to perform a search on a container of Atoms and check for either the Name or Element equality using my template predicate like so:
typedef std::string (Atom::*fn)() const;
Atom_it it = std::find_if( _atoms.begin(), _atoms.end(), mem_fun_eq <Atom, std::string> ((fn)&Atom::Name, atomname));
but compiling this returns the following error on the std::find_if line:
error: address of overloaded function with no contextual type information
Also, trying to form the same predicate for a check of the Element() as such:
typedef Atom::Element_t& (Atom::*fn)() const;
Atom_it it = std::find_if(_atoms.begin(), _atoms.end(), mem_fun_eq <Atom, Atom::Element_t> ((fn)&Atom::Element, elmt);
creates a different error!
error: no matching function for call to ‘mem_fun_eq<Atom, Atom::Element_t>::mem_fun_eq(Atom::Element_t& (Atom::*)()const, const Atom::Element_t&)’
note: candidates are: mem_fun_eq<U, R>::mem_fun_eq(R (U::*)(), R&) [with U = Atom, R = Atom::Element_t]
note: mem_fun_eq<Atom, Atom::Element_t>::mem_fun_eq(const mem_fun_eq<Atom, Atom::Element_t>&)
Firstly, am I reinventing the wheel with this predicate? Is there something in the STL that I've missed that does the same job in a single class? I can always break the predicate down into several more specific ones, but I'm trying to avoid that.
Secondly, can you help me with the compiler errors?
I don't know of any easy way to do this using the bits provided with the STL. There is probably some clever boost way, using iterator adapters, or boost::lambda, but personally I wouldn't go that way.
Obviously C++0x lambdas will make all this easy.
Your problem is attempting to cast a function like this:
const std::string&(Atom::*)()
into a function like this:
std::string (Atom::*)()
If you replace your typedef R (U::*fn_t)(); with typedef const R& (U::*fn_t)() const; then it should work.
The following avoids this problem and also provides type inference so that you can just write mem_fun_eq(&Atom::Name, atomname). It compiles for me, although I haven't tested it.
template<typename U, typename R, typename S>
class mem_fun_eq_t : public std::unary_function<U const*, bool>
{
private:
R (U::*fn_)() const;
S val_;
public:
mem_fun_eq_t(R (U::*fn )() const, S val) : fn_(fn), val_(val){}
bool operator()(U * u)
{
return (u->*fn_)() == val_;
}
};
template<typename U, typename R, typename S>
mem_fun_eq_t<U, R, S> mem_fun_eq(R (U::*fn)() const, S val)
{
return mem_fun_eq_t<U, R, S>(fn, val);
}
Have you thought of trying to mix in a mem_fun_ref or mem_fun object in place of the member function call?
Basically, you call on mem_fun to create an object that accepts two arguments T* and a template argument to the function A if it has one (or void if it doesn't). Hence you combine it like so:
template<typename MemFunc, typename CompareType, typename T>
struct MyPredicate{
MyPredicate(MemFunc _functionObj, CompareType _value)
: m_Value(_value),
m_Function(_functionObj){}
bool operator()(const T &_input){
return m_Value == m_Function(_input);
}
private:
MemFunc m_Function;
CompareType m_Value;
};
Edit:
Ok, that's not completely working so why not have:
struct NamePred: binary_function<Atom*,string,bool>{
bool operator()(Atom *_obj, string _val){
return _obj->Name() == _val;
};
};
then use bind2nd
find_if( atoms.begin(), atoms.end(), bind2nd( NamePred, "yo" ) );