如何在 c++ 中正确定义函数对象

How to properly define function objects in c++?

本文关键字:定义 函数 对象 c++      更新时间:2023-10-16

我在一个非常简单的代码上遇到了一个非常奇怪的错误,我无法修复。

我定义了以下函数对象:

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);
            }
};

在这里,类Point<n>之前已经很好地定义,用于在n维空间中存储点的n坐标(使用所需的运算符,...

我希望使用 L2Norm<5>(p) 获得点p(例如创建为 Point<5> p)的 l2 范数。但这给了我以下错误:

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>&’

我很确定我犯了一个非常愚蠢的错误,但我找不到在哪里!


附言作为一个附带问题,如果我只能说L2Norm(p)并且编译器从p中检测到模板参数会更好,但据我所知,这是不可能的。我说的对吗?

您需要创建一个实例并调用其运算符 () 。当前您正在尝试调用不存在的转换构造函数。

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

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

顺便说一句,您可能也希望使调用运算符const,因为对它们的调用不太可能导致实例的可观察状态发生变化:

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 { .... }
};

正如@juanchopanza已经回答的那样,您必须先创建对象:

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

现在,您甚至可以获得:

L2Norm()(p-q)

使用所谓的"多态函数对象"。通过使用模板operator()创建简单的类类型:

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);
    }
};

缺点是您无法将其设置为C++03的自适应二进制函数,因此它在某些C++03算法中不起作用。在 boost 中,如果您提供适当的定义,它将在 C++11 中,由于使用了 decltype ,它应该得到处理。

使用此技术,您可以消除冗余()

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.