Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QtConcurrent::mapped() with a member function complaining about error: no match for 'operator=' (operand types are 'QFuture<MainWindow::IntStruct>' and 'QFuture<void>')

QtConcurrent::mapped() with a member function complaining about error: no match for 'operator=' (operand types are 'QFuture<MainWindow::IntStruct>' and 'QFuture<void>')

Scheduled Pinned Locked Moved Solved General and Desktop
qt5qt5.13concurrentqfuture
5 Posts 3 Posters 1.2k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • CybeXC Offline
    CybeXC Offline
    CybeX
    wrote on last edited by
    #1

    I want to use the QtConcurrent::mapped() function, but going through the QtConcurrent examples provided and trying to find a usable example to extend to my use has been difficult.

    In the examples, Qt maps to static functions only, no member functions are used (many simliar mapped variations are found in the examples, but no member functions are used).

    The problem:

    QtConcurrent::map() applies a function to a Sequence or Iterator w/o returning i.e. QFuture<void>. However I wish to have the results returned i.e. QFuture<SomeStructOrType> from a member function.

    The example/scenario I want to use it in is an intensive workload in a UI application, but a simplied example could be:

    class MainWindow : public QMainWindow {
         Q_OBJECT
        
      public:
         // The struct is to demonstrate a datatype more complex than int / QString
         struct IntStruct {
             int i;
         };
    
         MainWindow(QWidget* parent = nullptr);
         IntStruct doubleValue(IntStruct i);
         ~MainWindow();
         
    private:
       Ui::MainWindow* ui;
       // To watch progress and act upon progress change
       QFutureWatcher<IntStruct> futureWatcher;
       
       // Member to keep track of mapped process
       QFuture<IntStruct> future;
       
       //...
    }
    

    The implementation being:

    MainWindow::MainWindow(QWidget* parent)
         : QMainWindow(parent)
         , ui(new Ui::MainWindow)
    {
         ui->setupUi(this);
    
         // Input Sequence/Iterator to perform doubleValue function on
         QList<IntStruct> intList = QList<IntStruct>();
         for (int i = 0; i < 1000; i++) {
             IntStruct s;
             s.i = qrand();
             intList.append(s);
         }
    
         // Watch future and report on result ready (process a result when done)
         connect(&futureWatcher, &QFutureWatcher<IntStruct>::resultReadyAt, this, [intList](int index){
             qDebug() << QString("[index = %1] value = %2").arg(QString::number(index), QString::number(intList.at(index).i));
         });
    
         //typedef IntStruct (MainWindow::*doubleValueFunction)(IntStruct);
         //doubleValueFunction memberFunction = this->doubleValue;             // this->doubleValue error: reference to non-static member function must be called ???
    
         // Run future - this doubleValue function should be a pointer to an instance function, how to do so?         
         future = QtConcurrent::mapped(intList, &MainWindow::doubleValue);
         futureWatcher.setFuture(future);
    }
    
    // Some complex member function
    MainWindow::IntStruct MainWindow::doubleValue(MainWindow::IntStruct i)
    {
        i.i *= i.i;
        return i;
    }
    

    I am aware that QtConcurrent allows lambdas, however I need to utilize a member function instead.

    I also attempted using a pointer to the current instance with a lambda, but it gave my a schpiel of errors, which you can find here.

     future = QtConcurrent::mapped(intList, [this](IntStruct &i){
         this->doubleValue(i);
     });
    

    TL;DR
    So basically, how can I use QtConcurrent::mapped() with a member function (in preferably a non-lambda version)?


    Some extra information:

    This is shown on screen

    enter image description here

    Error log when I try to compile:

    ..\ThreadTester\mainwindow.cpp: In constructor 'MainWindow::MainWindow(QWidget*)':
    ..\ThreadTester\mainwindow.cpp:27:69: error: no match for 'operator=' (operand types are 'QFuture<MainWindow::IntStruct>' and 'QFuture<void>')
          future = QtConcurrent::mapped(intList, &MainWindow::doubleValue);
                                                                         ^
    In file included from F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include\QtCore/QFuture:1:0,
                     from ..\ThreadTester\thread.h:10,
                     from ..\ThreadTester\mainwindow.h:6,
                     from ..\ThreadTester\mainwindow.cpp:1:
    F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include\QtCore/qfuture.h:59:7: note: candidate: QFuture<MainWindow::IntStruct>& QFuture<MainWindow::IntStruct>::operator=(const QFuture<MainWindow::IntStruct>&)
     class QFuture
           ^~~~~~~
    F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include\QtCore/qfuture.h:59:7: note:   no known conversion for argument 1 from 'QFuture<void>' to 'const QFuture<MainWindow::IntStruct>&'
    F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include\QtCore/qfuture.h:59:7: note: candidate: QFuture<MainWindow::IntStruct>& QFuture<MainWindow::IntStruct>::operator=(QFuture<MainWindow::IntStruct>&&)
    F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include\QtCore/qfuture.h:59:7: note:   no known conversion for argument 1 from 'QFuture<void>' to 'QFuture<MainWindow::IntStruct>&&'
    In file included from F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include/QtConcurrent/qtconcurrentfilterkernel.h:48:0,
                     from F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include\QtConcurrent/qtconcurrentfilter.h:47,
                     from F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include\QtConcurrent/QtConcurrent:8,
                     from ..\ThreadTester\thread.h:11,
                     from ..\ThreadTester\mainwindow.h:6,
                     from ..\ThreadTester\mainwindow.cpp:1:
    F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include/QtConcurrent/qtconcurrentmapkernel.h: In instantiation of 'QtConcurrent::ThreadEngineStarter<T> QtConcurrent::startMapped(const Sequence&, Functor) [with T = void; Sequence = QList<MainWindow::IntStruct>; Functor = QtConcurrent::MemberFunctionWrapper1<MainWindow::IntStruct, MainWindow, MainWindow::IntStruct>]':
    F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include\QtConcurrent/qtconcurrentmap.h:132:88:   required from 'QFuture<typename QtPrivate::MapResultType<void, MapFunctor>::ResultType> QtConcurrent::mapped(const Sequence&, MapFunctor) [with Sequence = QList<MainWindow::IntStruct>; MapFunctor = MainWindow::IntStruct (MainWindow::*)(MainWindow::IntStruct); typename QtPrivate::MapResultType<void, MapFunctor>::ResultType = void]'
    ..\ThreadTester\mainwindow.cpp:27:69:   required from here
    F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include/QtConcurrent/qtconcurrentmapkernel.h:237:71: error: could not convert 'QtConcurrent::startThreadEngine(ThreadEngine*) [with ThreadEngine = QtConcurrent::SequenceHolder1<QList<MainWindow::IntStruct>, QtConcurrent::MappedEachKernel<QList<MainWindow::IntStruct>::const_iterator, QtConcurrent::MemberFunctionWrapper1<MainWindow::IntStruct, MainWindow, MainWindow::IntStruct> >, QtConcurrent::MemberFunctionWrapper1<MainWindow::IntStruct, MainWindow, MainWindow::IntStruct> >; typename ThreadEngine::ResultType = MainWindow::IntStruct]()' from 'QtConcurrent::ThreadEngineStarter<MainWindow::IntStruct>' to 'QtConcurrent::ThreadEngineStarter<void>'
         return startThreadEngine(new SequenceHolderType(sequence, functor));
                                                                           ^
    F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include/QtConcurrent/qtconcurrentmapkernel.h: In instantiation of 'bool QtConcurrent::MappedEachKernel<Iterator, MapFunctor>::runIteration(Iterator, int, QtConcurrent::MappedEachKernel<Iterator, MapFunctor>::T*) [with Iterator = QList<MainWindow::IntStruct>::const_iterator; MapFunctor = QtConcurrent::MemberFunctionWrapper1<MainWindow::IntStruct, MainWindow, MainWindow::IntStruct>; QtConcurrent::MappedEachKernel<Iterator, MapFunctor>::T = MainWindow::IntStruct]':
    ..\ThreadTester\mainwindow.cpp:36:1:   required from here
    F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include/QtConcurrent/qtconcurrentmapkernel.h:175:17: error: no match for call to '(QtConcurrent::MemberFunctionWrapper1<MainWindow::IntStruct, MainWindow, MainWindow::IntStruct>) (const MainWindow::IntStruct&)'
             *result = map(*it);
    In file included from F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include\QtConcurrent/qtconcurrentfilter.h:48:0,
                     from F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include\QtConcurrent/QtConcurrent:8,
                     from ..\ThreadTester\thread.h:11,
                     from ..\ThreadTester\mainwindow.h:6,
                     from ..\ThreadTester\mainwindow.cpp:1:
    F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include/QtConcurrent/qtconcurrentfunctionwrappers.h:132:14: note: candidate: T QtConcurrent::MemberFunctionWrapper1<T, C, U>::operator()(C&, U) [with T = MainWindow::IntStruct; C = MainWindow; U = MainWindow::IntStruct]
         inline T operator()(C &c, U u)
                  ^~~~~~~~
    F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include/QtConcurrent/qtconcurrentfunctionwrappers.h:132:14: note:   candidate expects 2 arguments, 1 provided
    mingw32-make[1]: *** [Makefile.Debug:1117: debug/mainwindow.o] Error 1
    mingw32-make[1]: *** Waiting for unfinished jobs....
    mingw32-make[1]: Leaving directory 'C:/Users/CybeX/QtProjects/build-ThreadTester-Desktop_Qt_5_13_1_MinGW_32_bit-Debug'
    mingw32-make: *** [Makefile:38: debug] Error 2
    

    What does not make sense to me at all is mapped() returns some datatype U. If I changed the QFuture<IntStruct> to QFuture<void>, everyone is happy, but I cannot gather any results which defeats the purpose of the mapped() function in the first place.

    KroMignonK 1 Reply Last reply
    0
    • CybeXC CybeX

      I want to use the QtConcurrent::mapped() function, but going through the QtConcurrent examples provided and trying to find a usable example to extend to my use has been difficult.

      In the examples, Qt maps to static functions only, no member functions are used (many simliar mapped variations are found in the examples, but no member functions are used).

      The problem:

      QtConcurrent::map() applies a function to a Sequence or Iterator w/o returning i.e. QFuture<void>. However I wish to have the results returned i.e. QFuture<SomeStructOrType> from a member function.

      The example/scenario I want to use it in is an intensive workload in a UI application, but a simplied example could be:

      class MainWindow : public QMainWindow {
           Q_OBJECT
          
        public:
           // The struct is to demonstrate a datatype more complex than int / QString
           struct IntStruct {
               int i;
           };
      
           MainWindow(QWidget* parent = nullptr);
           IntStruct doubleValue(IntStruct i);
           ~MainWindow();
           
      private:
         Ui::MainWindow* ui;
         // To watch progress and act upon progress change
         QFutureWatcher<IntStruct> futureWatcher;
         
         // Member to keep track of mapped process
         QFuture<IntStruct> future;
         
         //...
      }
      

      The implementation being:

      MainWindow::MainWindow(QWidget* parent)
           : QMainWindow(parent)
           , ui(new Ui::MainWindow)
      {
           ui->setupUi(this);
      
           // Input Sequence/Iterator to perform doubleValue function on
           QList<IntStruct> intList = QList<IntStruct>();
           for (int i = 0; i < 1000; i++) {
               IntStruct s;
               s.i = qrand();
               intList.append(s);
           }
      
           // Watch future and report on result ready (process a result when done)
           connect(&futureWatcher, &QFutureWatcher<IntStruct>::resultReadyAt, this, [intList](int index){
               qDebug() << QString("[index = %1] value = %2").arg(QString::number(index), QString::number(intList.at(index).i));
           });
      
           //typedef IntStruct (MainWindow::*doubleValueFunction)(IntStruct);
           //doubleValueFunction memberFunction = this->doubleValue;             // this->doubleValue error: reference to non-static member function must be called ???
      
           // Run future - this doubleValue function should be a pointer to an instance function, how to do so?         
           future = QtConcurrent::mapped(intList, &MainWindow::doubleValue);
           futureWatcher.setFuture(future);
      }
      
      // Some complex member function
      MainWindow::IntStruct MainWindow::doubleValue(MainWindow::IntStruct i)
      {
          i.i *= i.i;
          return i;
      }
      

      I am aware that QtConcurrent allows lambdas, however I need to utilize a member function instead.

      I also attempted using a pointer to the current instance with a lambda, but it gave my a schpiel of errors, which you can find here.

       future = QtConcurrent::mapped(intList, [this](IntStruct &i){
           this->doubleValue(i);
       });
      

      TL;DR
      So basically, how can I use QtConcurrent::mapped() with a member function (in preferably a non-lambda version)?


      Some extra information:

      This is shown on screen

      enter image description here

      Error log when I try to compile:

      ..\ThreadTester\mainwindow.cpp: In constructor 'MainWindow::MainWindow(QWidget*)':
      ..\ThreadTester\mainwindow.cpp:27:69: error: no match for 'operator=' (operand types are 'QFuture<MainWindow::IntStruct>' and 'QFuture<void>')
            future = QtConcurrent::mapped(intList, &MainWindow::doubleValue);
                                                                           ^
      In file included from F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include\QtCore/QFuture:1:0,
                       from ..\ThreadTester\thread.h:10,
                       from ..\ThreadTester\mainwindow.h:6,
                       from ..\ThreadTester\mainwindow.cpp:1:
      F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include\QtCore/qfuture.h:59:7: note: candidate: QFuture<MainWindow::IntStruct>& QFuture<MainWindow::IntStruct>::operator=(const QFuture<MainWindow::IntStruct>&)
       class QFuture
             ^~~~~~~
      F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include\QtCore/qfuture.h:59:7: note:   no known conversion for argument 1 from 'QFuture<void>' to 'const QFuture<MainWindow::IntStruct>&'
      F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include\QtCore/qfuture.h:59:7: note: candidate: QFuture<MainWindow::IntStruct>& QFuture<MainWindow::IntStruct>::operator=(QFuture<MainWindow::IntStruct>&&)
      F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include\QtCore/qfuture.h:59:7: note:   no known conversion for argument 1 from 'QFuture<void>' to 'QFuture<MainWindow::IntStruct>&&'
      In file included from F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include/QtConcurrent/qtconcurrentfilterkernel.h:48:0,
                       from F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include\QtConcurrent/qtconcurrentfilter.h:47,
                       from F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include\QtConcurrent/QtConcurrent:8,
                       from ..\ThreadTester\thread.h:11,
                       from ..\ThreadTester\mainwindow.h:6,
                       from ..\ThreadTester\mainwindow.cpp:1:
      F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include/QtConcurrent/qtconcurrentmapkernel.h: In instantiation of 'QtConcurrent::ThreadEngineStarter<T> QtConcurrent::startMapped(const Sequence&, Functor) [with T = void; Sequence = QList<MainWindow::IntStruct>; Functor = QtConcurrent::MemberFunctionWrapper1<MainWindow::IntStruct, MainWindow, MainWindow::IntStruct>]':
      F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include\QtConcurrent/qtconcurrentmap.h:132:88:   required from 'QFuture<typename QtPrivate::MapResultType<void, MapFunctor>::ResultType> QtConcurrent::mapped(const Sequence&, MapFunctor) [with Sequence = QList<MainWindow::IntStruct>; MapFunctor = MainWindow::IntStruct (MainWindow::*)(MainWindow::IntStruct); typename QtPrivate::MapResultType<void, MapFunctor>::ResultType = void]'
      ..\ThreadTester\mainwindow.cpp:27:69:   required from here
      F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include/QtConcurrent/qtconcurrentmapkernel.h:237:71: error: could not convert 'QtConcurrent::startThreadEngine(ThreadEngine*) [with ThreadEngine = QtConcurrent::SequenceHolder1<QList<MainWindow::IntStruct>, QtConcurrent::MappedEachKernel<QList<MainWindow::IntStruct>::const_iterator, QtConcurrent::MemberFunctionWrapper1<MainWindow::IntStruct, MainWindow, MainWindow::IntStruct> >, QtConcurrent::MemberFunctionWrapper1<MainWindow::IntStruct, MainWindow, MainWindow::IntStruct> >; typename ThreadEngine::ResultType = MainWindow::IntStruct]()' from 'QtConcurrent::ThreadEngineStarter<MainWindow::IntStruct>' to 'QtConcurrent::ThreadEngineStarter<void>'
           return startThreadEngine(new SequenceHolderType(sequence, functor));
                                                                             ^
      F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include/QtConcurrent/qtconcurrentmapkernel.h: In instantiation of 'bool QtConcurrent::MappedEachKernel<Iterator, MapFunctor>::runIteration(Iterator, int, QtConcurrent::MappedEachKernel<Iterator, MapFunctor>::T*) [with Iterator = QList<MainWindow::IntStruct>::const_iterator; MapFunctor = QtConcurrent::MemberFunctionWrapper1<MainWindow::IntStruct, MainWindow, MainWindow::IntStruct>; QtConcurrent::MappedEachKernel<Iterator, MapFunctor>::T = MainWindow::IntStruct]':
      ..\ThreadTester\mainwindow.cpp:36:1:   required from here
      F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include/QtConcurrent/qtconcurrentmapkernel.h:175:17: error: no match for call to '(QtConcurrent::MemberFunctionWrapper1<MainWindow::IntStruct, MainWindow, MainWindow::IntStruct>) (const MainWindow::IntStruct&)'
               *result = map(*it);
      In file included from F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include\QtConcurrent/qtconcurrentfilter.h:48:0,
                       from F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include\QtConcurrent/QtConcurrent:8,
                       from ..\ThreadTester\thread.h:11,
                       from ..\ThreadTester\mainwindow.h:6,
                       from ..\ThreadTester\mainwindow.cpp:1:
      F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include/QtConcurrent/qtconcurrentfunctionwrappers.h:132:14: note: candidate: T QtConcurrent::MemberFunctionWrapper1<T, C, U>::operator()(C&, U) [with T = MainWindow::IntStruct; C = MainWindow; U = MainWindow::IntStruct]
           inline T operator()(C &c, U u)
                    ^~~~~~~~
      F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include/QtConcurrent/qtconcurrentfunctionwrappers.h:132:14: note:   candidate expects 2 arguments, 1 provided
      mingw32-make[1]: *** [Makefile.Debug:1117: debug/mainwindow.o] Error 1
      mingw32-make[1]: *** Waiting for unfinished jobs....
      mingw32-make[1]: Leaving directory 'C:/Users/CybeX/QtProjects/build-ThreadTester-Desktop_Qt_5_13_1_MinGW_32_bit-Debug'
      mingw32-make: *** [Makefile:38: debug] Error 2
      

      What does not make sense to me at all is mapped() returns some datatype U. If I changed the QFuture<IntStruct> to QFuture<void>, everyone is happy, but I cannot gather any results which defeats the purpose of the mapped() function in the first place.

      KroMignonK Offline
      KroMignonK Offline
      KroMignon
      wrote on last edited by
      #2

      @CybeX A written in documentation ==> https://doc.qt.io/qt-5/qtconcurrentmap.html#concurrent-map

      When using a modifier function, the futur will return void, not the parameter type.
      You have to change you function signature to:

       MainWindow::IntStruct doubleValue(MainWindow::IntStruct &i);
      

      It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

      1 Reply Last reply
      1
      • CybeXC Offline
        CybeXC Offline
        CybeX
        wrote on last edited by
        #3

        So I have 2 options available to me. I could use:

        • map() which changes values in-place (in the intList QList<IntStruct I pass in) with a QFuture<IntStruct> or
        • mapped() which uses a QFuture<void> and requires a call to QFuture::result() (which is blocking if no results are ready, I suggest connecting a QFutureWatcher<>::onResultReady() to it).

        to use member functions, I can either

        1. leave my QFuture<void> as shown in the docs by @KroMignon. It is not explicitly said, but it should be extracted from the provided example - an easy thing to miss.
        2. Alternatively, I can use use std::bind while keeping my QFuture<IntStream>
        future = QtConcurrent::map(intList, std::bind( 
                                                &MainWindow::doubleValue, 
                                                this, 
                                                std::placeholders::_1
                                             )
                                   );
        
        1 Reply Last reply
        0
        • VRoninV Offline
          VRoninV Offline
          VRonin
          wrote on last edited by
          #4

          The reason why there are no examples of QtConcurrent on non-static meber functions is because it's unsafe. If the object that has the method you are running gets deleted while QtConcurrent is running the program will segfault

          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
          ~Napoleon Bonaparte

          On a crusade to banish setIndexWidget() from the holy land of Qt

          1 Reply Last reply
          2
          • CybeXC Offline
            CybeXC Offline
            CybeX
            wrote on last edited by
            #5

            @VRonin
            Quite right - infact 101% correct.

            However, and you can correct me if I am wrong, but these mapped functions can be used for more than just transforming the datatype into another datatype. It does not always need to be 'instance based'. Let me explain what I mean (and what my thought process is)

            In Java (lang level 8), there is the introduction of the Stream API with a bunch of additional features such as lambdas, etc. One particularly useful example is something like

            List<SomeClass>  list = ...
            list.stream().map(o -> o.someMember).filter(o -> o.value < 2).collect(Collectors.asList());
            

            Now this simply takes an object (of type List), and runs a mapping functions (returning a stream object) and running a filter function on it (returning another stream object) followed by collecting all objects into a list.

            Now, my intention, specifically in this case is to utilize the filter & map functions similarly, but due to its design (QtConcurrent functions), I am breaking these functions up with signals (and slots) everywhere.

            This isn't part of the question, but for my own curiosity, if one had to mimik functions like this above, is there a...shorter way of doing the same thing rather than

            QFuture<SomeStruct> future = ...
            QFutureWatcher<SomeStruct> ...
            connect( //futurewatcher signal started with whatever)
            connect( //futurewatcher signal finished with whatever)
            QFutureWatcher::setFuture(future)
            ...
            

            just for one part of the function (i.e. mapping or filter)

            1 Reply Last reply
            0

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved