简体   繁体   中英

How to properly define function objects in c++?

I am getting a very strange error on a very simple code that I couldn't fix.

I have defined the following function object:

template<const size_t n> class L2Norm {
    public:
            double operator()(const Point<n>& p) {
                /* computes the L2-norm of the point P ... */

            }
            double operator()(const Point<n>& p,
                            const Point<n>& q) {
                    return L2Norm<n>(p-q);
            }
};

Here the class Point<n> is well defined before to store the n coordinates of a point in n -dimensional space (with required operators, ...).

I expect to get the l2-norm of a point p (created as Point<5> p for example) using L2Norm<5>(p) . But this gives me the following error:

no matching function for call to ‘L2Norm<5ul>::L2Norm(Point<5ul>&)’
note: candidates are: L2Norm<n>::L2Norm() [with long unsigned int n = 5ul]
note:   candidate expects 0 arguments, 1 provided
note: L2Norm<5ul>::L2Norm(const L2Norm<5ul>&)
note:   no known conversion for argument 1 from ‘Point<5ul>’ to ‘const L2Norm<5ul>&’

I'm pretty sure that I am doing a very stupid mistake but I cannot find out where!


PS As a side question, it would be much nicer if I could say L2Norm(p) only and the compiler detects the template parameter from p but to the best of my knowledge this is not possible. Am I right?

You need to create an instance and call its operator () . Currently you are trying to call a non-existent converting constructor.

return L2Norm<n>()(p-q); // C++03 and C++11
//              ^^

or

return L2Norm<n>{}(p-q);  // c++11
//              ^^

As an aside, you might want to make your call operators const too, since it is unlikely calls to them should result in a change to the observable state of an instance:

template<const size_t n> class L2Norm 
{
 public:
  double operator()(const Point<n>& p) const { .... }
  double operator()(const Point<n>& p, const Point<n>& q) const { .... }
};

As @juanchopanza's already answered, you have to create the object first:

L2Norm<5>()(p-q);

Now, you can even get:

L2Norm()(p-q)

using so called "polymorphic function object". By making a simple class type with template operator() instead:

class L2Norm {
public:
    template<const size_t n> 
    double operator()(const Point<n>& p) const {
        /* computes the L2-norm of the point P ... */
    }
    template<const size_t n> 
    double operator()(const Point<n>& p,
                      const Point<n>& q) const {
        return operator()(p-q);
    }
};

The disadvantage is that you can't make this an adaptable binary function for C++03, so it will not work in some C++03 algorithms. In boost it will if you provide appropriate definitions and in C++11 it should be handled thanks to use of decltype .

With this technique, you can eliminate the redundant () :

class {
public:
    template<const size_t n> 
    double operator()(const Point<n>& p) const {
        /* computes the L2-norm of the point P ... */
    }
    template<const size_t n> 
    double operator()(const Point<n>& p,
                      const Point<n>& q) const {
        return operator()(p-q);
    }
} L2Norm;

L2norm(p-q); // Uses the object L2Norm, which has an unnamed type.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM