QtConcurrent::blockingMapped using lambdas not working



  • Qt: 5.9.0
    gcc: 7.1.1
    OS: linux x86 64bit
    When using QtConcurrent::blockingMapped I get wrong types being deduced and it tries to instanciate QVector<void> internally and fails... It comes from the template parameter IntermediateType in template for startMappedReduced... you can see the full template instantiation stack here:

    /usr/include/qt/QtCore/qvector.h: In instantiation of ‘class QVector<void>’:
    /usr/include/qt/QtConcurrent/qtconcurrentreducekernel.h:82:16:   required from ‘class QtConcurrent::IntermediateResults<void>’
    /usr/include/qt/QtCore/qmap.h:113:7:   required from ‘struct QMapNode<int, QtConcurrent::IntermediateResults<void> >’
    /usr/include/qt/QtCore/qmap.h:248:21:   required from ‘void QMapData<Key, T>::destroy() [with Key = int; T = QtConcurrent::IntermediateResults<void>]’
    /usr/include/qt/QtCore/qmap.h:339:43:   required from ‘QMap<K, V>::~QMap() [with Key = int; T = QtConcurrent::IntermediateResults<void>]’
    /usr/include/qt/QtConcurrent/qtconcurrentreducekernel.h:100:7:   required from ‘QtConcurrent::MappedReducedKernel<ReducedResultType, Iterator, MapFunctor, ReduceFunctor, Reducer>::MappedReducedKernel(Iterator, Iterator, MapFunctor, ReduceFunctor, QtConcurrent::ReduceOptions) [with ReducedResultType = QList<int>; Iterator = QList<QImage>::iterator; MapFunctor = MainWindow::gl3ch()::<lambda(const QImage&)>; ReduceFunctor = QtPrivate::PushBackWrapper; Reducer = QtConcurrent::ReduceKernel<QtPrivate::PushBackWrapper, QList<int>, void>; QtConcurrent::ReduceOptions = QFlags<QtConcurrent::ReduceOption>]’
    /usr/include/qt/QtConcurrent/qtconcurrentmapkernel.h:257:30:   required from ‘QtConcurrent::ThreadEngineStarter<ResultType> QtConcurrent::startMappedReduced(Iterator, Iterator, MapFunctor, ReduceFunctor, QtConcurrent::ReduceOptions) [with IntermediateType = void; ResultType = QList<int>; Iterator = QList<QImage>::iterator; MapFunctor = MainWindow::gl3ch()::<lambda(const QImage&)>; ReduceFunctor = QtPrivate::PushBackWrapper; QtConcurrent::ReduceOptions = QFlags<QtConcurrent::ReduceOption>]’
    /usr/include/qt/QtConcurrent/qtconcurrentmap.h:241:9:   required from ‘ResultType QtConcurrent::blockingMappedReduced(Iterator, Iterator, MapFunctor, ReduceFunctor, QtConcurrent::ReduceOptions) [with ResultType = QList<int>; Iterator = QList<QImage>::iterator; MapFunctor = MainWindow::gl3ch()::<lambda(const QImage&)>; ReduceFunctor = QtPrivate::PushBackWrapper; QtConcurrent::ReduceOptions = QFlags<QtConcurrent::ReduceOption>]’
    /usr/include/qt/QtConcurrent/qtconcurrentmap.h:290:9:   required from ‘Sequence QtConcurrent::blockingMapped(Iterator, Iterator, MapFunctor) [with Sequence = QList<int>; Iterator = QList<QImage>::iterator; MapFunctor = MainWindow::gl3ch()::<lambda(const QImage&)>]’
    

    That is because the type typename QtPrivate::MapResultType<void, MapFunctor>::ResultType is void for some reason when i use a lambda and it's ok when it's a regular function pointer.
    My test code looks like this:

        QList<QImage> images;
        QList<int> thumbnails = QtConcurrent::blockingMapped<QList<int>>(images.begin(), images.end(), test);
    

    And when test is defined as this it fails:

        auto test = [](const QImage&) -> int {
            return 1;
        };
    

    But this works:

    int test(const QImage&){
        return 1;
    }
    

    I don't know what I'm doing wrong. Because I took a similar example from the Qt documentation and it didn't compile because it was not able to deduce the type so I had to play around with it manually adding that template parameter as blockingMapped<QList<int>> which I find ridiculous on its own. Getting Qt to work with lambdas seems pretty clumsy and difficult... So my question is: What am I doing wrong?/How to do it properly using lambdas


  • Qt Champions 2016

    @petoknm said in QtConcurrent::blockingMapped using lambdas not working:

    And when test is defined as this it fails:

    Where is this? Could you provide the whole snippet that fails?


  • Lifetime Qt Champion

    Hi,

    Might be a silly question but did you saw the Using Lambdas in QtConcurrent::run document ?



  • @SGaist
    Yeah I also read the map example which at the bottom provides a lambda example that doesn't compile.



  • And I also thing the code is wrong and should return a future of a list of images... not just a future of image...



  • I made a repo showcasing the problem. The code is exactly what the document about concurrent map showed how to do it... So either I'm doing something wrong or the documentation is wrong. I get the following compilation error:

    [ 25%] Automatic MOC for target example
    [ 25%] Built target example_autogen
    [ 50%] Building CXX object CMakeFiles/example.dir/main.cpp.o
    /home/peter/Qt/example/main.cpp: In function ‘int main(int, char**)’:
    /home/peter/Qt/example/main.cpp:14:54: error: conversion from ‘QFuture<void>’ to non-scalar type ‘QFuture<QImage>’ requested
         QFuture<QImage> thumbnails = QtConcurrent::mapped(images, [](const QImage &img) {
                                      ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
             return img.scaledToWidth(100, Qt::SmoothTransformation);
             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         });
         ~~                                                
    In file included from /usr/include/qt/QtConcurrent/qtconcurrentfilterkernel.h:48:0,
                     from /usr/include/qt/QtConcurrent/qtconcurrentfilter.h:47,
                     from /usr/include/qt/QtConcurrent/QtConcurrent:6,
                     from /home/peter/Qt/example/main.cpp:4:
    /usr/include/qt/QtConcurrent/qtconcurrentmapkernel.h: In instantiation of ‘class QtConcurrent::MappedEachKernel<QList<QImage>::const_iterator, main(int, char**)::<lambda(const QImage&)> >’:
    /usr/include/qt/QtConcurrent/qtconcurrentmapkernel.h:211:8:   required from ‘struct QtConcurrent::SequenceHolder1<QList<QImage>, QtConcurrent::MappedEachKernel<QList<QImage>::const_iterator, main(int, char**)::<lambda(const QImage&)> >, main(int, char**)::<lambda(const QImage&)> >’
    /usr/include/qt/QtConcurrent/qtconcurrentmapkernel.h:235:30:   required from ‘QtConcurrent::ThreadEngineStarter<T> QtConcurrent::startMapped(const Sequence&, Functor) [with T = void; Sequence = QList<QImage>; Functor = main(int, char**)::<lambda(const QImage&)>]’
    /usr/include/qt/QtConcurrent/qtconcurrentmap.h:179:88:   required from ‘QFuture<typename QtPrivate::MapResultType<void, MapFunctor>::ResultType> QtConcurrent::mapped(const Sequence&, MapFunctor) [with Sequence = QList<QImage>; MapFunctor = main(int, char**)::<lambda(const QImage&)>; typename QtPrivate::MapResultType<void, MapFunctor>::ResultType = void]’
    /home/peter/Qt/example/main.cpp:16:6:   required from here
    /usr/include/qt/QtConcurrent/qtconcurrentmapkernel.h:163:7: error: no type named ‘result_type’ in ‘struct main(int, char**)::<lambda(const class QImage&)>’
     class MappedEachKernel : public IterateKernel<Iterator, typename MapFunctor::result_type>
           ^~~~~~~~~~~~~~~~
    /usr/include/qt/QtConcurrent/qtconcurrentmapkernel.h:166:46: error: no type named ‘result_type’ in ‘struct main(int, char**)::<lambda(const class QImage&)>’
         typedef typename MapFunctor::result_type T;
                                                  ^
    /usr/include/qt/QtConcurrent/qtconcurrentmapkernel.h: In instantiation of ‘struct QtConcurrent::SequenceHolder1<QList<QImage>, QtConcurrent::MappedEachKernel<QList<QImage>::const_iterator, main(int, char**)::<lambda(const QImage&)> >, main(int, char**)::<lambda(const QImage&)> >’:
    /usr/include/qt/QtConcurrent/qtconcurrentmapkernel.h:235:30:   required from ‘QtConcurrent::ThreadEngineStarter<T> QtConcurrent::startMapped(const Sequence&, Functor) [with T = void; Sequence = QList<QImage>; Functor = main(int, char**)::<lambda(const QImage&)>]’
    /usr/include/qt/QtConcurrent/qtconcurrentmap.h:179:88:   required from ‘QFuture<typename QtPrivate::MapResultType<void, MapFunctor>::ResultType> QtConcurrent::mapped(const Sequence&, MapFunctor) [with Sequence = QList<QImage>; MapFunctor = main(int, char**)::<lambda(const QImage&)>; typename QtPrivate::MapResultType<void, MapFunctor>::ResultType = void]’
    /home/peter/Qt/example/main.cpp:16:6:   required from here
    /usr/include/qt/QtConcurrent/qtconcurrentmapkernel.h:219:10: error: ‘void QtConcurrent::SequenceHolder1<Sequence, Base, Functor>::finish() [with Sequence = QList<QImage>; Base = QtConcurrent::MappedEachKernel<QList<QImage>::const_iterator, main(int, char**)::<lambda(const QImage&)> >; Functor = main(int, char**)::<lambda(const QImage&)>]’ marked ‘override’, but does not override
         void finish() override
              ^~~~~~
    /usr/include/qt/QtConcurrent/qtconcurrentmapkernel.h: In instantiation of ‘QtConcurrent::ThreadEngineStarter<T> QtConcurrent::startMapped(const Sequence&, Functor) [with T = void; Sequence = QList<QImage>; Functor = main(int, char**)::<lambda(const QImage&)>]’:
    /usr/include/qt/QtConcurrent/qtconcurrentmap.h:179:88:   required from ‘QFuture<typename QtPrivate::MapResultType<void, MapFunctor>::ResultType> QtConcurrent::mapped(const Sequence&, MapFunctor) [with Sequence = QList<QImage>; MapFunctor = main(int, char**)::<lambda(const QImage&)>; typename QtPrivate::MapResultType<void, MapFunctor>::ResultType = void]’
    /home/peter/Qt/example/main.cpp:16:6:   required from here
    /usr/include/qt/QtConcurrent/qtconcurrentmapkernel.h:235:29: error: no matching function for call to ‘startThreadEngine(SequenceHolderType*)’
         return startThreadEngine(new SequenceHolderType(sequence, functor));
                ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    In file included from /usr/include/qt/QtConcurrent/qtconcurrentiteratekernel.h:49:0,
                     from /usr/include/qt/QtConcurrent/qtconcurrentfilterkernel.h:47,
                     from /usr/include/qt/QtConcurrent/qtconcurrentfilter.h:47,
                     from /usr/include/qt/QtConcurrent/QtConcurrent:6,
                     from /home/peter/Qt/example/main.cpp:4:
    /usr/include/qt/QtConcurrent/qtconcurrentthreadengine.h:263:63: note: candidate: template<class ThreadEngine> QtConcurrent::ThreadEngineStarter<typename ThreadEngine::ResultType> QtConcurrent::startThreadEngine(ThreadEngine*)
     inline ThreadEngineStarter<typename ThreadEngine::ResultType> startThreadEngine(ThreadEngine *threadEngine)
                                                                   ^~~~~~~~~~~~~~~~~
    /usr/include/qt/QtConcurrent/qtconcurrentthreadengine.h:263:63: note:   template argument deduction/substitution failed:
    In file included from /usr/include/qt/QtConcurrent/qtconcurrentfilterkernel.h:48:0,
                     from /usr/include/qt/QtConcurrent/qtconcurrentfilter.h:47,
                     from /usr/include/qt/QtConcurrent/QtConcurrent:6,
                     from /home/peter/Qt/example/main.cpp:4:
    /usr/include/qt/QtConcurrent/qtconcurrentmapkernel.h: At global scope:
    /usr/include/qt/QtConcurrent/qtconcurrentmapkernel.h:213:5: error: ‘QtConcurrent::SequenceHolder1<Sequence, Base, Functor>::SequenceHolder1(const Sequence&, Functor) [with Sequence = QList<QImage>; Base = QtConcurrent::MappedEachKernel<QList<QImage>::const_iterator, main(int, char**)::<lambda(const QImage&)> >; Functor = main(int, char**)::<lambda(const QImage&)>]’, declared using local type ‘main(int, char**)::<lambda(const QImage&)>’, is used but never defined [-fpermissive]
         SequenceHolder1(const Sequence &_sequence, Functor functor)
         ^~~~~~~~~~~~~~~
    make[2]: *** [CMakeFiles/example.dir/build.make:63: CMakeFiles/example.dir/main.cpp.o] Error 1
    make[1]: *** [CMakeFiles/Makefile2:68: CMakeFiles/example.dir/all] Error 2
    make: *** [Makefile:84: all] Error 2
    

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.