C++ lambda ambiguous call

99封情书 提交于 2021-01-29 08:17:41

问题


I am trying to have two eachPixel functions. One returns an image, and the other returns nothing. I'm getting "call to eachPixel is ambiguous" even though I am specifying the return type of the lambda.

How can I resolve the ambiguity?

// this one does not return an image
void eachPixel(const QImage &image, const std::function <void (uint)>& pixelFunc, const QRect &bounds=QRect()) {
...

    for (int y=region.y(); y<=region.bottom(); y++) {
        for (int x=region.x(); x<=region.right(); x++) {
            pixelFunc(image.pixel(x,y));
        }
    }
}

// This one returns an image
QImage eachPixel(const QImage &image, const std::function <uint (uint)>& pixelFunc, const QRect &bounds=QRect()) {
...

    QImage out(image.size(), image.format());
    for (int y=region.y(); y<=region.bottom(); y++) {
        for (int x=region.x(); x<=region.right(); x++) {
            out.setPixel(x,y, pixelFunc(image.pixel(x,y)));
        }
    }
    return out;
}

void test_pixelFunc() {
    QImage image(300,200, QImage::Format_ARGB32);
    image.fill(Qt::blue);

    QImage out = eachPixel(image, [] (uint p) -> uint { //uint specified!!
        return qRgb(qRed(p), qBlue(p), qGreen(p)); // swap green and blue channels
    }, QRect (0,0, 300, 200));
    out.save("test_pixelfunc.png");


    int accumulator=0;
    eachPixel(image, [&accumulator](uint p) -> void { // void specified!
        accumulator++;
    }, QRect (0,0, 300, 200));
    qDebug() << "accumulator" << accumulator;

};

回答1:


You can use templates and SFINAE on the return type of the function you pass in.

#include <iostream>
#include <functional>

template <typename T, std::enable_if_t<std::is_same_v<void, decltype(std::declval<T>()(1))>, int> = 0>
void foo (T f) {
    // std::function<void(int)> func = f;
    // if you really need a std::function
    f(1);
}

template <typename T, std::enable_if_t<std::is_same_v<int, decltype(std::declval<T>()(1))>, int> = 0>
int foo (T f) {
    return f(1);
}

int main() {
    foo([](int x) { std::cout << "void " << x << '\n'; });

    foo([](int x) { std::cout << "int\n"; return x; });
}

For c++11 you can use std::is_same and std::enable_if directly.

template <typename T, typename std::enable_if<std::is_same<void, decltype(std::declval<T>()(1))>::value, int>::type = 0>
void foo (T f) {
    f(1);
}

template <typename T, typename std::enable_if<std::is_same<int, decltype(std::declval<T>()(1))>::value, int>::type = 0>
int foo (T f) {
    return f(1);
}



回答2:


You can add ignored parameter to one of lambdas to help resolve ambiguity:

struct noreturn_tag {};
void foo( std::function<void(int,noreturn_tag)>);
void foo( std::function<int(int)>);

int main() {
    foo( []( int ) { return 0; } );
    foo( []( int, noreturn_tag ) {} );
}

live example



来源:https://stackoverflow.com/questions/50629394/c-lambda-ambiguous-call

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!