the_naive
the_naive

Reputation: 3064

Error while returning boolean from lambda expressions

bool markersFormRectangle = [](std::vector<cv::Point2f> markerCoords) {
  cv::Point2f center(
    (markerCoords[0].x + markerCoords[1].x + markerCoords[2].x + markerCoords[3].x) / 4,
    (markerCoords[0].y + markerCoords[1].y + markerCoords[2].y + markerCoords[3].y) / 4
  );

  float dd1 = cv::norm(center - markerCoords[0]);
  float dd2 = cv::norm(center - markerCoords[1]);
  float dd3 = cv::norm(center - markerCoords[2]);
  float dd4 = cv::norm(center - markerCoords[3]);

  return (fabs(dd1-dd2) < 5) && (fabs(dd1 - dd3) < 5) && (fabs(dd1 - dd4) < 5);
};

I am trying to use the above stated lambda expressions which checks if the four points form a near rectangular shape. But the compiler complains with the error: called object type 'bool' is not a function or function pointer when I try to use the lambda expression in an if statement the following way:

if (markersFormRectangle(markerPoints)) {
    //do something
}

When I change the return type auto it doesn't give me that error. I'm pretty new to using lambda functors. Could you please tell me what I am doing wrong and why the compiler doesn't give anymore error if the type is changed to auto?

Upvotes: 1

Views: 157

Answers (2)

Vlad from Moscow
Vlad from Moscow

Reputation: 311048

In this declaration

        bool markersFormRectangle = [](std::vector<cv::Point2f> markerCoords)
        {
            cv::Point2f center((markerCoords[0].x +markerCoords[1].x + markerCoords[2].x + markerCoords[3].x) / 4,
                    (markerCoords[0].y +markerCoords[1].y + markerCoords[2].y + markerCoords[3].y) / 4);

            float dd1 = cv::norm(center - markerCoords[0]);
            float dd2 = cv::norm(center - markerCoords[1]);
            float dd3 = cv::norm(center - markerCoords[2]);
            float dd4 = cv::norm(center - markerCoords[3]);

            return (fabs(dd1-dd2) < 5) && (fabs(dd1 - dd3) < 5) && (fabs(dd1 - dd4) < 5);
        };

the initializer is a lambda expression while the declared variable has the type bool. There is no implicit or context-dependent conversion from the type of a lambda expression to the type bool.

Take into account that each lambda has its own unique type.

So you have to write

        auto markersFormRectangle = [](std::vector<cv::Point2f> markerCoords)
        {
            cv::Point2f center((markerCoords[0].x +markerCoords[1].x + markerCoords[2].x + markerCoords[3].x) / 4,
                    (markerCoords[0].y +markerCoords[1].y + markerCoords[2].y + markerCoords[3].y) / 4);

            float dd1 = cv::norm(center - markerCoords[0]);
            float dd2 = cv::norm(center - markerCoords[1]);
            float dd3 = cv::norm(center - markerCoords[2]);
            float dd4 = cv::norm(center - markerCoords[3]);

            return (fabs(dd1-dd2) < 5) && (fabs(dd1 - dd3) < 5) && (fabs(dd1 - dd4) < 5);
        };

From the C++14 Standard (5.1.2 Lambda expressions)

3 The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed nonunion class type — called the closure type — whose properties are described below. This class type is neither an aggregate (8.5.1) nor a literal type (3.9)....

To specify explicitly the lambda return type you could write using the trailing return type specifier

        auto markersFormRectangle = [](std::vector<cv::Point2f> markerCoords) -> bool
        {
            cv::Point2f center((markerCoords[0].x +markerCoords[1].x + markerCoords[2].x + markerCoords[3].x) / 4,
                    (markerCoords[0].y +markerCoords[1].y + markerCoords[2].y + markerCoords[3].y) / 4);

            float dd1 = cv::norm(center - markerCoords[0]);
            float dd2 = cv::norm(center - markerCoords[1]);
            float dd3 = cv::norm(center - markerCoords[2]);
            float dd4 = cv::norm(center - markerCoords[3]);

            return (fabs(dd1-dd2) < 5) && (fabs(dd1 - dd3) < 5) && (fabs(dd1 - dd4) < 5);
        };

though it unnecessary.

Bear in mind that (5.1.2 Lambda expressions)

7 The lambda-expression’s compound-statement yields the function-body (8.4) of the function call operator,...

Upvotes: 5

Alan Birtles
Alan Birtles

Reputation: 36459

Lambdas can only be stored in a variable of type auto or converted to a function pointer (e.g. using std::function), if you want to get the result of your lambda you need to call it fist. Your code should be either:

auto markers = []{ return true; };
bool value = markers();

or

bool value = []{ return true; }();

depending on whether you are trying to store the lambda or its result.

Upvotes: 3

Related Questions