How to pass overloaded function to an operator? - c++

I need to pass a function to an operator. Any unary function having correct arg type. Return type can be anything. Because this is library code, I can not wrap it or cast f to specific overload (outside of operator*). Function takes operator* 1st arg as it own argument. Artificial example below compiles and returns correct results. But it has hardcoded int return type—to make this example compile.
#include <tuple>
#include <iostream>
using namespace std;
template<typename T>
int operator* (T x, int& (*f)(T&) ) {
return (*f)(x);
};
int main() {
tuple<int,int> tpl(42,43);
cout << tpl * get<0>;
}
Is it possible to make operator* to accept f with arbitrary return type?
UPDATE - GCC bug?
Code:
#include <tuple>
template<typename T, typename U>
U operator* (T x, U& (*f)(T&) ) {
return (*f)(x);
};
int main() {
std::tuple<int,int> tpl(42,43);
return tpl * std::get<0,int,int>;
}
Compiles and runs correctly with gcc462 and 453 but is reject with gcc471 and 480. So it is possible GCC regression bug. I've submitted bug report:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54111
EDIT
I've changed example to use tuple as arg - it was possible trivially deduce return type in previous example.
EDIT2
Many people could not understand what is needed, so I've changed call function to operator* to make example more real.

Yes, if this is what you mean:
template<typename T, typename F>
auto call (T x, F f) -> decltype(f(x)) {
return (f)(x);
}
There are actually a lot of ways to do that.

As an answer to your updated question:
as discussed by #DavidRodríguez, get<0> is not enough, nor the syntatically correct &get<0>. What you need is &get<0,int,int>. Follows your example, it would be:
#include <tuple>
using namespace std;
template<typename T, typename U>
U call (T x, U (*f)(T&) ) {
return (*f)(x);
};
int main() {
tuple<int,int> tpl(42,43);
call(tpl, &get<0,int,int>);
return 0;
}
During normal use of std::get<>(), the int,int part is deduced automatically. But in your situation you need to provide it, since there is no parameters. One workaround is a custom get template function:
#include <tuple>
using namespace std;
template <size_t I, typename T>
auto myGet(T& tpl) -> decltype(get<I>(tpl))
{
return get<I>(tpl);
}
template<typename T, typename U>
U call (T x, U (*f)(T&) ) {
return (*f)(x);
};
int main() {
tuple<int,int> tpl(42,43);
auto get0 = &myGet<0, decltype(tpl)>;
call(tpl, get0);
// call(tpl, &myGet<0, decltype(tpl)>); // all in one line, do not work
return 0;
}

You should be able to do this:
template<typename T,typename U>
U call (T x, U (*f)(T) ) {
return (*f)(x);
};

Related

Function template specialization with const ref arguments

The following code compiles fine.
#include <iostream>
struct rgb8{
uint8_t r() const {return 0;};
};
template<typename L, typename P>
L pixelToLevel(P p) {
return static_cast<L>(p);
}
template<>
uint8_t pixelToLevel<uint8_t, rgb8>(rgb8 p) { // <---------- line X
return pixelToLevel<uint8_t, uint8_t>(p.r());
}
int main()
{
pixelToLevel<uint8_t>(rgb8());
return 0;
}
But if in line X I change rgb8 p to const rgb8& p, it fails to compile.
(The exact compiler error generated depends on whether or not the explicit template argument rgb8 is also changed to const rgb8&.)
How can I get it to compile if I want to pass p by reference rather than by value on line X?
You need to change the template parameter in the declaration of specialization, and template argument when calling it too. Otherwise the primary template would be called instead. e.g.
template<>
uint8_t pixelToLevel<uint8_t, const rgb8&>(const rgb8& p) { // <---------- line X
return pixelToLevel<uint8_t, uint8_t>(p.r());
}
then
pixelToLevel<uint8_t, const rgb8&>(rgb8());
LIVE
EDIT
Given pixelToLevel<uint8_t>(rgb8());, template argument deduction is performed with primary template and P is deduced as rgb8 (it won't be deduced as const rgb8& with current primary template's parameter declaration), then the specialization version won't be called.
You can apply overloading instead of template specialization. e.g.
template<typename L, typename P>
L pixelToLevel(P p) {
return static_cast<L>(p);
}
template<typename L>
L pixelToLevel(const rgb8& p) { // <---------- line X
return pixelToLevel<L, uint8_t>(p.r());
}
Then pixelToLevel<uint8_t>(rgb8()); would select the 2nd overload.
LIVE
An alternate solution to #songyuanyao's would be
template<typename L, typename P>
L pixelToLevel(const P& p) {
return static_cast<L>(p);
}

Addition of variable number of numbers

I am trying to write a function which accepts multiple arguments of different data types and return the sum of numbers. It should be able to decide what data type to be used for sum. For e.g.
if I write add(3,1,2,3) it should return sum as an int. However, if I write add(3,1,2.5,3.25) it should return sum as a double.
I tried using template, but giving compile time error. Here is the function
template <typename T>
T add(int n, ...)
{
T sum = 0;
va_list vl;
va_start(vl,n);
for(int i=0;i<n;i++)
{
sum += va_arg(vl,T);
}
va_end(vl);
return sum;
}
int main()
{
std::cout<<add(3,1,2,3);
return 0;
}
Compile Error: no matching function for call to 'add(int, int, int, int)'.
I think error is coming because I passed in va_arg T, but i don't know what else to pass to keep it generalised.
You should replace
std::cout<<add(3,1,2,3);
with
std::cout<<add<int>(3,1,2,3); // explicitly, int, double, float whatever
To make the code run succesfully as the compiler is unable to deduce the typename from implicit call.
Live code example here
Your function returns the value of type T, but you don't specify any argument of type T, making it impossible for compiler to deduce the type.
Other solution would be to add an overload that works for add(0) and pass first argument in add of type T. This can achieve OP's implicit deduction goal. Now compiler can deduce return type from first argument.
#include <cstdarg>
#include <iostream>
#include <cassert>
using namespace std;
int add(int n)
{
assert(0 == n);
return 0;
}
template <typename T>
T add(int n, T first, ...)
{
T sum = first;
va_list vl;
va_start(vl,first);
for(int i=1;i<n;i++)
{
sum += va_arg(vl,T);
}
va_end(vl);
return sum;
}
int main()
{
std::cout<<add(3,1,2,3);
std::cout<<add(3,1.5,2.,3.5);
return 0;
}
live code here
Why don't you use Varidaic Templates? – Mohit Jain
If you can write in C++14:
template<typename T>
inline T sum(T t){
return t;
}
template<typename T, typename... Ts>
inline auto sum(T t, Ts... ts){
return t+sum(ts...);
}
#include<iostream>
int main(){
std::cout<<sum(2.5, 2)<<'\n'
<<sum(2, 2.5)<<'\n'
<<sum(1u, 2.5, 3.f, '0')<<'\n';
}
If you write in C++11 under MSVC++ (it doesn't work under g++):
template<typename T>
inline T sum(T t){
return t;
}
template<typename T, typename... Ts>
inline auto sum(T t, Ts... ts)->decltype(t+sum(ts...)){
return t+sum(ts...);
}
#include<iostream>
int main(){
std::cout<<sum(2.5, 2)<<'\n' //works
<<sum(2, 2.5)<<'\n' //works
<<sum(1u, 2.5, 3.f, '0')<<'\n';//works under VC++, but not under g++
}
i think the problem is you determined the parameter type as int try to use
instead of: T Add (int n,...)
use: T Add( T n, ...)

c++11: How to write a wrapper function to make `std::function` objects

I am trying to write a wrapper make_function, which like std::make_pair can create a std::function object out of suitable callable objects.
Just like make_pair, for a function pointer foo, auto f0 = make_function(foo); creates a std::function function object f0 of the right type signature.
Just to clarify, I don't mind occasionally giving type parameters to make_function in case it is difficult (or impossible) to deduce the type entirely from the parameters.
What I came up with so far (code below) works fine for lambdas, some function pointers, and functors (I didn't consider volatiles). But I couldn't get it work for std::bind or std::bind<R> results. In the code below
auto f2 = make_function(std::bind(foo,_1,_2,_3)); //not OK
wouldn't compile/work, with gcc 4.8.1. I am guessing that I didn't capture the operator() for the bind result correctly, but I am not sure how to fix it.
Any help on how to fix this case or improvement in other corner cases is appreciated.
My question is, of course, how to fix the error in the example below.
For background, one of the cases I use this wrapper can be found at this question: How to make C++11 functions taking function<> parameters accept lambdas automatically. If you do not approve the use of std::function or my specific way of using it, please leave your comments in that post, and discuss technical issues here.
--- EDIT ---
From some of the comments, I learned that it's because of the ambiguity issue (ambiguity of the function call operator() of std::bind results). As pointed out by #Mooing Duck's answer, the solution is to give the parameter types explicitly. I have updated the code to combine the three functions in #Mooing Duck's answer (with slight change of type parameters), so that the make_function wrapper can now handle/type-deduce unambiguous cases as before, and allow specification of complete type signature when there is ambiguity.
(My original code for the unambiguous cases is at: https://stackoverflow.com/a/21665705/683218 and can be tested at: https://ideone.com/UhAk91):
#include <functional>
#include <utility>
#include <iostream>
#include <functional>
using namespace std;
// For generic types that are functors, delegate to its 'operator()'
template <typename T>
struct function_traits
: public function_traits<decltype(&T::operator())>
{};
// for pointers to member function
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const> {
enum { arity = sizeof...(Args) };
typedef function<ReturnType (Args...)> f_type;
};
// for pointers to member function
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) > {
enum { arity = sizeof...(Args) };
typedef function<ReturnType (Args...)> f_type;
};
// for function pointers
template <typename ReturnType, typename... Args>
struct function_traits<ReturnType (*)(Args...)> {
enum { arity = sizeof...(Args) };
typedef function<ReturnType (Args...)> f_type;
};
template <typename L>
static typename function_traits<L>::f_type make_function(L l){
return (typename function_traits<L>::f_type)(l);
}
//handles bind & multiple function call operator()'s
template<typename ReturnType, typename... Args, class T>
auto make_function(T&& t)
-> std::function<decltype(ReturnType(t(std::declval<Args>()...)))(Args...)>
{return {std::forward<T>(t)};}
//handles explicit overloads
template<typename ReturnType, typename... Args>
auto make_function(ReturnType(*p)(Args...))
-> std::function<ReturnType(Args...)> {
return {p};
}
//handles explicit overloads
template<typename ReturnType, typename... Args, typename ClassType>
auto make_function(ReturnType(ClassType::*p)(Args...))
-> std::function<ReturnType(Args...)> {
return {p};
}
// testing
using namespace std::placeholders;
int foo(int x, int y, int z) { return x + y + z;}
int foo1(int x, int y, int z) { return x + y + z;}
float foo1(int x, int y, float z) { return x + y + z;}
int main () {
//unambuiguous
auto f0 = make_function(foo);
auto f1 = make_function([](int x, int y, int z) { return x + y + z;});
cout << make_function([](int x, int y, int z) { return x + y + z;})(1,2,3) << endl;
int first = 4;
auto lambda_state = [=](int y, int z) { return first + y + z;}; //lambda with states
cout << make_function(lambda_state)(1,2) << endl;
//ambuiguous cases
auto f2 = make_function<int,int,int,int>(std::bind(foo,_1,_2,_3)); //bind results has multiple operator() overloads
cout << f2(1,2,3) << endl;
auto f3 = make_function<int,int,int,int>(foo1); //overload1
auto f4 = make_function<float,int,int,float>(foo1); //overload2
return 0;
}
Ideone
The problem is your code doesn't handle lambdas, bind, or functionoids properly, your code assumes that all of these take no parameters. To handle these, you'll have to specify the parameter types:
//plain function pointers
template<typename... Args, typename ReturnType>
auto make_function(ReturnType(*p)(Args...))
-> std::function<ReturnType(Args...)>
{return {p};}
//nonconst member function pointers
template<typename... Args, typename ReturnType, typename ClassType>
auto make_function(ReturnType(ClassType::*p)(Args...))
-> std::function<ReturnType(Args...)>
{return {p};}
//const member function pointers
template<typename... Args, typename ReturnType, typename ClassType>
auto make_function(ReturnType(ClassType::*p)(Args...) const)
-> std::function<ReturnType(Args...)>
{return {p};}
//qualified functionoids
template<typename FirstArg, typename... Args, class T>
auto make_function(T&& t)
-> std::function<decltype(t(std::declval<FirstArg>(), std::declval<Args>()...))(FirstArg, Args...)>
{return {std::forward<T>(t)};}
//unqualified functionoids try to deduce the signature of `T::operator()` and use that.
template<class T>
auto make_function(T&& t)
-> decltype(make_function(&std::remove_reference<T>::type::operator()))
{return {std::forward<T>(t)};}
Variables:
int func(int x, int y, int z) { return x + y + z;}
int overloaded(char x, int y, int z) { return x + y + z;}
int overloaded(int x, int y, int z) { return x + y + z;}
struct functionoid {
int operator()(int x, int y, int z) { return x + y + z;}
};
struct functionoid_overload {
int operator()(int x, int y, int z) { return x + y + z;}
int operator()(char x, int y, int z) { return x + y + z;}
};
int first = 0;
auto lambda = [](int x, int y, int z) { return x + y + z;};
auto lambda_state = [=](int x, int y, int z) { return x + y + z + first;};
auto bound = std::bind(func,_1,_2,_3);
Tests:
std::function<int(int,int,int)> f0 = make_function(func); assert(f0(1,2,3)==6);
std::function<int(char,int,int)> f1 = make_function<char,int,int>(overloaded); assert(f1(1,2,3)==6);
std::function<int(int,int,int)> f2 = make_function<int,int,int>(overloaded); assert(f2(1,2,3)==6);
std::function<int(int,int,int)> f3 = make_function(lambda); assert(f3(1,2,3)==6);
std::function<int(int,int,int)> f4 = make_function(lambda_state); assert(f4(1,2,3)==6);
std::function<int(int,int,int)> f5 = make_function<int,int,int>(bound); assert(f5(1,2,3)==6);
std::function<int(int,int,int)> f6 = make_function(functionoid{}); assert(f6(1,2,3)==6);
std::function<int(int,int,int)> f7 = make_function<int,int,int>(functionoid_overload{}); assert(f7(1,2,3)==6);
std::function<int(char,int,int)> f8 = make_function<char,int,int>(functionoid_overload{}); assert(f8(1,2,3)==6);
http://coliru.stacked-crooked.com/a/a9e0ad2a2da0bf1f The only reason your lambda was succeeding is because it was implicitly convertible to a function pointer because your example doesn't capture any state. Note that my code requires the parameter types for overloaded functions, functionoids with overloaded operator() (including bind), but is now able to deduce all non-overloaded functionoids.
The decltype lines are complicated but they're used to deduce the return types. Notice that in NONE of my tests do I need to specify the return type. Let's break down make_function<short,int,int> down as if T is char(*)(short, int, int):
-> decltype(t(std::declval<FirstArg>(), std::declval<Args>()...))(FirstArg, Args...)
`std::declval<FirstArg>()` is `short{}` (roughly)
-> decltype(t(short{}, std::declval<Args>()...))(FirstArg, Args...)
`std::declval<Args>()...` are `int{}, int{}` (roughly)
-> decltype(t(short{}, int{}, int{})(FirstArg, Args...)
`t(short{}, int{}, int{})` is an `int{}` (roughly)
-> decltype(short{})(FirstArg, Args...)
`decltype(int{})` is `int`
-> int(FirstArg, Args...)
`FirstArg` is still `short`
-> int(short, Args...)
`Args...` are `int, int`
-> int(short, int, int)
So this complex expression merely figures out the function's signature
well, that should look familiar...
In general you cannot solve it without the severe restriction that whatever you pass to make_function is only callable with exactly one signature.
What are you going to do with something like:
struct Generic
{
void operator()() { /* ... */ }
void operator()() const { /* ... */ }
template<typename T, typename... Ts>
T operator()(T&& t, Ts&&...) { /* ... */ }
template<typename T, typename... Ts>
T operator()(T&& t, Ts&&...) const { /* ... */ }
};
C++14 generic lambdas will have the same issue.
The signature in std::function is based on how you plan to call it and not on how you construct/assign it.
You cannot solve it for std::bind either, as that has indefinite arity:
void foo() { std::cout << "foo()" << std::endl; }
//...
auto f = std::bind(foo);
f(); // writes "foo()"
f(1); // writes "foo()"
f(1, 2, 3, 4, 5, 6); // writes "foo()"
The big reason why you want to be able to convert lambdas to std::function is because you want two overloads, each taking different signatures.
A good way to solve this involves std::result_of.
Suppose you are making a loop control structure that takes a lambda or other functional. If that functional returns void, you want to loop uncontrolled. If it returns bool or the like, you want to loop while it returns true. If it returns enum ControlFlow, you want to pay attention to the ControlFlow return value (continue or break, say). The function in question takes either the element iterating over, and optionally some extra data (the index in the iteration, maybe some "location" meta-information about the element, etc).
std::result_of would let you pretend to invoke the passed in type with a different number of arguments. A traits class could then figure out which of the above signatures is the "best match", and then route to the implementation that handles that signature (possibly by wrapping the "simpler" cases in a lambda and calling the more complex cases).
Naively, your make_function would could this problem, because you could then simply overload on the various std::function< blah(etc) > cases. But with auto parameters coming down the pipe, and std::bind already doing perfect forwarding, this only handles the easiest cases.
std::result_of traits classes (and possibly related concept matching and requires clauses) and tag dispatching (or SFINAE as a last resort).
The big downside is that you end up having to manage the override order yourself semi-manually. I could see some utility in helper classes where you provide a list of signatures to match, and it either produces a boost::variant or you also produce a canonical output and a conversion method to that canonical output.
The short answer? std::bind's implementation is implementation specific details, but it may involve the equivalent of perfect forwarding of variadic parameter packs, and as such is not suitable for your "get the address of the one and only concrete operator()" technique you are using.
As another example:
template <typename A,typename B>
vector<B> map(std::function<B (A)> f, vector<A> arr) {
vector<B> res;
for (int i=0;i<arr.size();i++) res.push_back(f(arr[i]));
return res;
}
should be written as:
template<typename expression>
using result = typename std::result_of<expression>::type;
template<typename expression>
using decayed_result = typename std::decay<result<expression>>::type;
template <typename function,typename B>
vector<decayed_result<function(B)>> map(function&& f, vector<A> const& arr) {
vector<decayed_result<function(B)>> res;
res.reserve( arr.size() );
for (A const& a : arr) {
res.push_back( f(a) );
}
return res;
}
again, result_of is the right solution, not converting things needlessly to std::function.
For fold_right we get:
template<bool b, typename T=void>
using EnableIf = typename std::enable_if<b,T>::type;
template<typename function, typename src, typename dest>
EnableIf<
std::is_convertible< result<function(src, dest)>, dest >::value,
std::vector<dest>
>
fold_right( function&& f, std::vector<src> const& v, dest initial )
which again skips any type erasure on f. And if you really want to do type erasure on f, you can do:
template<typename T> struct identity { typedef T type; };
template<typename T> using do_not_deduce = typename identity<T>::type;
template<typename src, typename dest>
std::vector<dest> fold_right( do_not_deduce< std::function<dest(src,dest)> > f, std::vector<src> const& v, dest init );
std::function is a type erasure object. You type erase because you want to use a type somewhere you do not want to carry the type over to. Deducing from a type what kind of resulting type erasure object you should create is almost always the wrong answer, because you have all of the dependency of non-type erased cases, and all of the inefficiency of the type erasure.
make_function's result is dependent the full type of the source, which makes type erasure output almost completely useless.

Passing an integer or a type as a template parameter?

Here is an example case of what I'm trying to do (it is a "test" case just to illustrate the problem) :
#include <iostream>
#include <type_traits>
#include <ratio>
template<int Int, typename Type>
constexpr Type f(const Type x)
{
return Int*x;
}
template<class Ratio, typename Type,
class = typename std::enable_if<Ratio::den != 0>::type>
constexpr Type f(const Type x)
{
return (x*Ratio::num)/Ratio::den;
}
template</*An int OR a type*/ Something, typename Type>
constexpr Type g(const Type x)
{
return f<Something, Type>(x);
}
int main()
{
std::cout<<f<1>(42.)<<std::endl;
std::cout<<f<std::kilo>(42.)<<std::endl;
}
As you can see, there are two versions of the f() function : the first one takes an int as a template parameter, and the second one takes a std::ratio. The problem is the following :
I would like to "wrap" this function through g() which can take an int OR a std::ratio as first template parameter and call the good version of f().
How to do that without writing two g() functions ? In other words, what do I have to write instead of /*An int OR a type*/ ?
Here's how I would do it, but I've changed your interface slightly:
#include <iostream>
#include <type_traits>
#include <ratio>
template <typename Type>
constexpr
Type
f(int Int, Type x)
{
return Int*x;
}
template <std::intmax_t N, std::intmax_t D, typename Type>
constexpr
Type
f(std::ratio<N, D> r, Type x)
{
// Note use of r.num and r.den instead of N and D leads to
// less probability of overflow. For example if N == 8
// and D == 12, then r.num == 2 and r.den == 3 because
// ratio reduces the fraction to lowest terms.
return x*r.num/r.den;
}
template <class T, class U>
constexpr
typename std::remove_reference<U>::type
g(T&& t, U&& u)
{
return f(static_cast<T&&>(t), static_cast<U&&>(u));
}
int main()
{
constexpr auto h = g(1, 42.);
constexpr auto i = g(std::kilo(), 42.);
std::cout<< h << std::endl;
std::cout<< i << std::endl;
}
42
42000
Notes:
I've taken advantage of constexpr to not pass compile-time constants via template parameters (that's what constexpr is for).
g is now just a perfect forwarder. However I was unable to use std::forward because it isn't marked up with constexpr (arguably a defect in C++11). So I dropped down to use static_cast<T&&> instead. Perfect forwarding is a little bit overkill here. But it is a good idiom to be thoroughly familiar with.
How to do that without writing two g() functions ?
You don't. There is no way in C++ to take either a type or a value of some type, except through overloading.
It is not possible to have a template parameter taking both type and non-type values.
Solution 1:
Overloaded functions.
Solution 2:
You can store values in types. Ex:
template<int n>
struct store_int
{
static const int num = n;
static const int den = 1;
};
template<class Ratio, typename Type,
class = typename std::enable_if<Ratio::den != 0>::type>
constexpr Type f(const Type x)
{
return (x*Ratio::num)/Ratio::den;
}
template<typename Something, typename Type>
constexpr Type g(const Type x)
{
return f<Something, Type>(x);
}
But with this solution you will have to specify g<store_int<42> >(...) instead of g<42>(...)
If the function is small, I advise you to use overloading.

Generic equivalent to std function objects

Is there any function objects in the boost that are generic equivalents to the std::equal_to, std::greater etc. family of function objects?
Essentially, std::equal_to should become something like
struct generic_equal_to
{
template <class T, class U>
bool operator()(const T& t, const U& u) const
{
return t == u;
}
};
I can see how the generic versions of std::plus etc. might be trickier due to issues with the return type (though the decltype can solve that). I can't see any possible reason why the std::equal_to function object itself should require a template argument, though.
Surely somewhere in boost or in the STL these versions exist? They are, of course, trivial to write, but I very much dislike duplicating library code, especially for something as apparently trivial as this.
EDIT:
As some context as to why I would want this instead of using lambdas, or another function-object generation method:
I was writing a generic boost::fusion sequence comparison function thusly:
template <class T>
bool sequence_equal(const T& left, const T& right)
{
return fusion::all(
fusion::zip(left, right),
fusion::fused<generic_equal_to>());
}
Note the fusion::fused<generic_equal_to> part, which leads to the isse that you can't practically specify a boost::lambda or boost::phoenix function-object by type. I guess one solution might be decltype:
fusion::fused<decltype(_1 == _2)>()
That seems very awkward though, and might not even work, depending on how boost::lambda or boost::phoenix is implemented - I'm really not sure.
I know you can use fusion::make_fused to get around this whole issue, but then you have to instantiate the function object. The solution I thought of, then, would be a non-template equal_to struct - I called mine generic_equal_to.
I know it's a very trivial problem - after all, make_fused(_1 == _2) will probably inline down to much the same assembly as fused<generic_equal_to>. I just couldn't believe that there was no generic_equal_to function object in boost or in the STL anywhere, hence this question.
I don't think there's anything quite as direct as you're asking for, but there are utilities that not only cover your use-cases, but go beyond. They are Boost.Lambda and Boost.Phoenix (the latter being a more generic successor to the lambda library).
Example using Boost.Lambda for generic equality:
#include <boost/lambda/lambda.hpp>
#include <iomanip>
#include <iostream>
struct foo {};
bool operator==(foo, foo) { return true; }
bool operator==(foo, int) { return false; }
template <typename T, typename U, typename Func>
void f(const T& x, const U& y, Func func)
{
std::cout << func(x, y) << std::endl;
}
int main()
{
using namespace boost::lambda; // for placeholders
std::cout << std::boolalpha;
foo a, b;
int i = 0;
f(a, b, _1 == _2);
f(a, i, _1 == _2);
}
And the same, with Phoenix:
#include <boost/phoenix.hpp>
#include <iomanip>
#include <iostream>
struct foo {};
bool operator==(foo, foo) { return true; }
bool operator==(foo, int) { return false; }
template <typename T, typename U, typename Func>
void f(const T& x, const U& y, Func func)
{
std::cout << func(x, y) << std::endl;
}
int main()
{
using namespace boost::phoenix::arg_names; // for placeholders
std::cout << std::boolalpha;
foo a, b;
int i = 0;
f(a, b, arg1 == arg2);
f(a, i, arg1 == arg2);
}
Each of these can be extended to support the other operators in the obvious way (and more generally, into other expressions). I would personally go with Phoenix, because if you find out you need more functionality than lambda offers you won't end up including both.
Now in C++14 there is std::equal_to<void> (that can be also used as std::equal_to<>)
std::equal_to<> is a specialization of std::equal_to with parameter and return type deduced.
template< class T, class U>
constexpr auto operator()( T&& lhs, U&& rhs ) const
-> decltype(std::forward<T>(lhs) == std::forward<U>(rhs));
Returns the result of equality comparison between lhs and rhs.
Docs