Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

Can someone explain what's going on in this code? (C++)

  1. May 28, 2014 #1
    I was looking at an example from here: http://cboard.cprogramming.com/cplusplus-programming/133294-passing-operator-parameter.html

    Code (Text):

    template <class T> bool myfunc(bool lv, bool rv, T oper)
    {
        return oper(lv, rv);
    }
     
    struct Or
    {
        bool operator()(bool lv, bool rv)
        {
            return lv || rv;
        }
    };
     
    int main()
    {
        bool result = myfunc(true, false, Or());
        return 0;
    }
     
    I'm confused about what it means to pass "Or()" into the function. "Or" is a type of struct and he's passing it in what an empty parantheses. Not sure how that has any meaning.
     
  2. jcsd
  3. May 28, 2014 #2

    DrClaude

    User Avatar

    Staff: Mentor

  4. May 28, 2014 #3

    Borek

    User Avatar

    Staff: Mentor

    Looks like () is an overloaded operator.
     
  5. May 28, 2014 #4
  6. May 28, 2014 #5

    Borek

    User Avatar

    Staff: Mentor

    "In a class definition, the default access for members and base classes is private. In a struct definition, the default is public. That is the only difference between a class and a struct."
     
  7. May 28, 2014 #6

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    Or() creates an instance of struct Or using the default constructor (not specified, so the freebie provided by the compiler is used). Note also, and this is very important, that struct Or defines a function operator that takes two bools and returns a bool. The function operator is <return_type> operator() (<argument_list>).

    Objects such as that instance of struct Or are called function objects, or functors. The C++ standard library makes extensive use of functors. The function operator is a bit funky on first blush, but it is quite powerful. Functors can hold value. Try the following, which should work in both C++03 and C++11:

    Code (Text):
    #include <iostream>

    // Function template for performing some operation <N> times.
    // oper must be a functor that defines member functions name() and operator()().
    template <int N, typename T>
    void apply_N_times (T oper) {
       // Call oper as an object. Functions can't do this. Functors can.
       std::cout << "Applying " << oper.name() << ' ' << N << " times.\n";

       // Call oper as a function N times. Functions can do this, but it's kinda boring.
       // With functors, interesting things can happen because functors can hold state.
       for (int ii = 0; ii < N; ++ii) {
          std::cout << ii << ":" << oper() << "\n";
       }  
    }


    // apply_N_times compatible class that boringly counts.
    class count {
    public:
       count() : value(0) {}
       std::string name() { return "count"; }
       int operator()() { return value++; }
    private:
       int value;
    };


    // apply_N_times compatible class that produces the Fibonacci sequence.
    class fib {
    public:
       fib() : prev(1), value(0) {}
       std::string name() { return "Fibonacci sequence"; }
       int operator()() {  
          int ret = value;
          value += prev;
          prev = ret;
          return ret;
       }  
    private:
       int prev, value;
    };


    int main () {
       apply_N_times<10> (count());
       apply_N_times<10> (fib());
    }
     
     
    Last edited: May 28, 2014
  8. May 28, 2014 #7

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    Functors are not function pointers. Functors (function objects) are moving toward making functions first class objects in C++. C++11 has gone even further in this regard. It adds std::function, std::bind, and one other little thing: Lambda expressions. Lambda expressions are massively powerful little beasties.
     
  9. May 28, 2014 #8
    In function 'int main()':
    Line 42: error: reference to 'count' is ambiguous
    compilation terminated due to -Wfatal-errors.
     
  10. May 28, 2014 #9

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    What compiler are you using? It works fine for me, with gnu and clang, and with c++03 and c++11.
     
  11. May 28, 2014 #10
    I was using this http://codepad.org/ stupid interpreter.
     
  12. May 28, 2014 #11

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    Codepad has problems. This time the problem is that it apparently is leaking std::count into the global namespace. My code works fine on ideone.com, and also works on codepad if you change count to Count.
     
  13. May 28, 2014 #12
    Ok, here's my first time using a functor. You're going to think this is the most pointless program ever. Just for the heck of it, I'm making a library of functions for Group Theory. I could use some suggestions for how to improve my isGroup function.



    Code (Text):

    #include <set>
    #include <iostream>

    template <typename ObType, typename BinaryFunction>
    bool isGroup(const std::set<ObType> & S, BinaryFunction & op)
    {
        /*
           isGroup returns true or false depending on whether the set S
           along with the operator op is a group in the Algebraic sense.
           That is, S is a group if and only if all the 4 following
           conditions are true:
                (1) If a, b in S, then a op b in S
                (2) If a, b, c in S, then (a + b) + c = a + (b + c)
                (3) There is an element 0 in S such that a + 0 = 0 + a for all a in S
                (4) If a in S, then there is a b in S such that a + b = b + a = 0
        */
        typename std::set<ObType>::const_iterator beg(S.cbegin()), offend(S.cend());
        bool noProblemsYet(true), foundIdentity(false);
        ObType iden;
        for (typename std::set<ObType>::const_iterator ia = beg; ia != offend && noProblemsYet; ++ia)
        {
            bool isIdentity = true;
            for (typename std::set<ObType>::const_iterator ib = beg; ib != offend && noProblemsYet; ++ib)
            {
                // ---------- (1) --------------
                if (S.count(op(*ia, *ib)) == 0)
                    noProblemsYet = false;
                // ---------- (3) --------------
                if (op(*ia, *ib) != op(*ib, *ia))
                    isIdentity = false;
                // -----------------------------
                for (typename std::set<ObType>::const_iterator ic = beg; ic != offend && noProblemsYet; ++ic)
                {
                    // ---------- (2) -------------
                    if (op(op(*ia, *ib), *ic) != op(*ia, op(*ib, *ic)))
                        noProblemsYet = false;
                    // ----------------------------
                }
            }
            if (isIdentity)
            {
                foundIdentity = true;
                iden = *ia;
            }
        }
       
        if (noProblemsYet)
        {
            if (!foundIdentity)
                noProblemsYet = false;
            for (typename std::set<ObType>::const_iterator ia = beg; ia != offend && noProblemsYet; ++ia)
            {
                bool foundInverse = false;
                for (typename std::set<ObType>::const_iterator ib = beg; ib != offend && noProblemsYet; ++ib)
                {
                    if (op(*ia, *ib) == op(*ib, *ia) && op(*ia, *ib) == iden)
                    {
                        foundInverse = true;
                        break;
                    }
                }
                // ---------- (4) -------------
                if (!foundInverse)
                    noProblemsYet = false;
                // ----------------------------
            }
        }

        return noProblemsYet;
    }

    /* ----------------------------- Functors --------------------------------------*/

    template <typename T>
    class Adder
    {
        private:
            static const char symbol = '+';
        public:
            T operator() (const T & x, const T & y) { return x + y; }; 
            char getSymbol(void) { return symbol; };
    };


    template <typename T>
    class Subtracter
    {
        private:
            static const char symbol = '-';
        public:
            T operator() (const T & x, const T & y) { return x - y; };
            char getSymbol(void) { return symbol; };
    };

    template <typename T>
    class Multiplier
    {
        private:
            static const char symbol = '*';
        public:
            T operator() (const T & x, const T & y) { return x * y; };
            char getSymbol(void) { return symbol; };
    };

    template <typename T>
    class Divider
    {
        private:
            static const char symbol = '/';
        public:
            T operator() (const T & x, const T & y) { return x / y; };
            char getSymbol(void) { return symbol; };
    };

    template <typename T>
    class Modder
    {
        private:
            static const char symbol = '%';
        public:
            T operator() (const T & x, const T & y) { return x % y; };
            char getSymbol(void) { return symbol; };
    };

    /* ------------------------------------------------------------------------------*/


    int main()
    {
        std::set<int> S1 = { 0, 1, -1 };
        std::set<int> S2 = { 0 };
        class Adder<int> p;
        std::cout << isGroup(S1, p);
        return 0;
    }
     
     
  14. May 29, 2014 #13

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    Your test for an identity element is wrong. Your code if (op(*ia, *ib) != op(*ib, *ia)) { isIdentity = false; } clears isIdentity when the group operation is non-commutative. You should be checking whether op(*ia, *ib) != *ib.
     
  15. May 29, 2014 #14
    Actually, shouldn't I be looking at

    Code (Text):

    (op(*ia, *ib) != op(*ib, *ia) || op(*ib, *ia) != *ib)
     
    ?????

    Wikipedia's page (http://en.wikipedia.org/wiki/Group_(mathematics [Broken])) says the identity element must satisfy 0 + a = a + 0 = a.
     
    Last edited by a moderator: May 6, 2017
Know someone interested in this topic? Share this thread via Reddit, Google+, Twitter, or Facebook