17

I want to refer to function pointers of built-in operators, but I don't know how to specify the specific type overloads.

I have the following template class signature:

template<typename ParamsType, typename FnCompareType>
class MyAction
{
public:
    MyAction(ParamsType& arg0, ParamsType& arg1, FnCompareType& fnCpmpare) 
    : arg0_(arg0), arg1_(arg1), fnCompare_(fnCpmpare) {}

    bool operator()()
    {
        if((*fnCompare_)(arg0_,arg1_)
        {
            // do this
        }
        else
        {
            // do s.th. else
        }
    }

private:
    ParamsType& arg0_;
    ParamsType& arg1_;
    FnCompareType& fnCompare_;
}

And want to use a syntax like this:

void doConditional(int param1, int param2)
{
    MyAction<int,&::operator>=> action(param1,param2);
    if(action())
    {
        // Do this
    }
    else
    {
        // Do that
    }
}

But that doesn't compile:

error: ‘::operator>=’ has not been declared

What can I do to refer to such intrinsic static operations?

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • `ACTION_P1(MyAction,fnCompare) { ... }` Does this even compile? Where are the return type and the types of the parameters? – Code-Apprentice Jul 14 '13 at 23:57
  • @MonadNewb Yes, it does! The real definition is even more complex. [tag:googlemock] defers the types of action parameters through a template parameter list. – πάντα ῥεῖ Jul 15 '13 at 00:00
  • Thank you for removing the details of googlemock in order to make your question more clear. For future reference, when you do this kind of simplification to get to the core issues of your question, you should make an example that compiles with plain-ol' C++ so that others can copy and paste the code and compile it as-is. – Code-Apprentice Jul 15 '13 at 18:18
  • @MonadNewb I think pixelchemist's answer would fairly fit for an answer to a canonical question about this topic. What should be changed to make this question a canonical one, or is there already s.th. similar asked? – πάντα ῥεῖ Jul 15 '13 at 19:36
  • Yes, pixelchemist gives a very thorough and complete answer. IMO, you should modify your example code so that it will compile without relying on any third-party libraries. From the way I read your code, `ACTION_P1` is supposed to be a function name. However, I don't see a return type. Also its parameters only have names, not types. – Code-Apprentice Jul 15 '13 at 21:04
  • @MonadNewb _`ACTION_P1` is supposed to be a function name_ Not really, it's a macro that defines a template class. But I'll try to change it for a common sample and use a simple function for that. – πάντα ῥεῖ Jul 16 '13 at 06:29
  • "it's a macro that defines a template class" So in other words, your example depends on a third-party library that someone reading this question needs to install in order to compile your example code. Is this macro important to the question regarding operators and function pointers? If not, it is an extra detail that makes this question slightly less useful as a "canonical" one. – Code-Apprentice Jul 16 '13 at 21:04
  • @MonadNewb I'm not sure if my edits resemble the problem correctly, could you have a look plz ... – πάντα ῥεῖ Jul 16 '13 at 21:33
  • That definitely looks a lot better. – Code-Apprentice Jul 16 '13 at 21:37

3 Answers3

23

Built-in operators

Why you cannot have function pointers of them:

C++11, §13.6/1, [over.built]

The candidate operator functions that represent the built-in operators defined in Clause 5 are specified in this subclause. These candidate functions participate in the operator overload resolution process as described in 13.3.1.2 and are used for no other purpose.

Built-in operators (those for the built-in types) aren't real operator functions. So you can't have function pointer pointing to them. You also cannot invoke them using operator<(A,B) syntax. They only participate in overload resolution but the compiler will translate them directly into the appropriate asm/machine instruction without any kind of "function call".

The way to get around this issue:

user1034749 has already answered this question, but for completeness:

The standard defines a lot of function objects in §20.8, [function.objects], i.e.

  • Arithmetic operations
  • Comparisons
  • Logic operations
  • Bitwise operations

A function object is an object of a function object type. In the places where one would expect to pass a pointer to a function to an algorithmic template (Clause 25), the interface is specified to accept a function object. This not only makes algorithmic templates work with pointers to functions, but also enables them to work with arbitrary function objects.

C++11, §20.8.5, [comparisons]

  • equal_to
  • not_equal_to
  • greater, less
  • greater_equal
  • less_equal

Those are templated function objects which decay to the analogous operator in their operator() function. They can be used as function pointer arguments.

user1034749 is right, I want to state: There's no other way, these are completely equivalent in usage to 'raw' function pointers. Reference given.

Standard class type operators

You can use standard library operators as function pointers (which are present as "real functions").

But you'll have to refer to the respective instance of the template. The compiler will need appropriate hints to deduce the correct template.

This works for me on MSVC 2012 using operator+ of std::basic_string

template<class Test>
Test test_function (Test const &a, Test const &b, Test (*FPtr)(Test const &, Test const &))
{
   return FPtr(a, b);
}

int main(int argc, char* argv[])
{
   typedef std::char_traits<char> traits_t;
   typedef std::allocator<char> alloc_t;
   std::basic_string<char, traits_t, alloc_t> a("test"), b("test2");
   std::cout << test_function<std::basic_string<char, traits_t, alloc_t>>(a, b, &std::operator+) << std::endl;
   return 0;
}

If the template argument of test_function is left out to be deduced this will fail (at least for MSVC 2012).

Community
  • 1
  • 1
Pixelchemist
  • 24,090
  • 7
  • 47
  • 71
9

You can use the same solution as used in C++ standard library:

std::sort (numbers, numbers+5, std::greater<int>());

where greater is

template <class T> struct greater : binary_function <T,T,bool> {
    bool operator() (const T& x, const T& y) const {return x>y;}
};

in your case http://www.cplusplus.com/reference/functional/greater_equal/

About reference of built operator.

You can reference existing operator< for any class (of course if they are not private, protected or your class/function not friend). But opeator< for builtin types (bool, short, int, double) it is not possible reference. Event if not look at C++ standard you can see from my text above.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
fghj
  • 8,898
  • 4
  • 28
  • 56
  • THX! Already found how to use this. Sorry I've edited my question to get a general answer if it's somehow possible to refer to these operator functions. – πάντα ῥεῖ Jul 14 '13 at 23:54
  • @g-makulik The Standard Library provides named functions that wrap most of the built-in operators. – Code-Apprentice Jul 14 '13 at 23:55
  • @g-makulik I guess I don't understand what kind of "general answer" you are looking for then. You can refer to the "operator functions" by the names given by the Standard Library. – Code-Apprentice Jul 14 '13 at 23:58
  • 1
    @MonadNewb Again: I know that. But these are a bit different from 'raw' function pointers, aren't they? These are structs with an appropriate `operator()` definiton, and you'll need an instance to call them. – πάντα ῥεῖ Jul 15 '13 at 00:04
  • In C++11 you can use lambda functions instead without defining new struct with opeator() – fghj Jul 15 '13 at 00:06
  • @g-makulik What do you mean by "'raw' function pointers"? Perhaps this is where the confusion lies. – Code-Apprentice Jul 15 '13 at 18:13
  • @MonadNewb The problem for me was to get the calling syntax deferred as in my original sample (`(*fnCompare)(arg0->x(),arg0->y())`). Deferring would (should) work correctly with such _'raw' function pointer_ that holds the address of any static or global function. I had to change the call syntax a bit, to get it working. – πάντα ῥεῖ Jul 15 '13 at 18:29
0

An extension to the solution provided by fghj, that would work for assignment type operators, such as +=/-=, etc would be to wrap these similarly to the standard variants. You could then do:

#include <iostream>

template <typename T>
struct assign_plus {
    void operator() const (T& a, const T& b){
        a += b;
    }
};

template <typename T>
struct assign_minus {
    void operator() const (T& a, const T& b){
        a -= b;
    }
};


template<template <class T> class O> requires requires(int& a, const int& b){
    { O<int>{}(a,b) };
}
void example(int& a, const int& b){
    O<int>{}(a,b);
}

int main(){
    int a = 5;
    int b = 6;
    example<assign_plus>(a,b);
    std::cout << a << "\n";
    example<assign_minus>(a,b);
    std::cout << a << "\n";
    return 0;
}

where the constraint could be kept/removed given c++20 compatibility. These constraints then also could be extended to require that a += b is valid (for custom types for example).

Lala5th
  • 1,137
  • 7
  • 18