std :: visit не распознает типы - PullRequest
1 голос
/ 20 февраля 2020

Я озадачен тем, что после некоторого рефакторинга кода следующий фрагмент кода больше не работает, так как в нем происходит переход к случаю auto, auto и игнорирование Complex, Complex. По общему признанию, я не совсем понимаю, что делает перегрузка точно , но для меня два кода выглядят абсолютно одинаково, за исключением того, что каждый получает свои параметры напрямую, тогда как другой имеет параметры, определенные в самом теле функции.

Math_Node Function_Manager::add(const Math_Node& arg){
        Math_Object obj1 = arg.children_ptr()->at(0)->data();
        Math_Object obj2 = arg.children_ptr()->at(1)->data();
        if( std::holds_alternative<Complex>(obj1) ){
            std::cerr << "obj1 is complex\n";
        }
        if( std::holds_alternative<Complex>(obj2) ){
            std::cerr << "obj2 is complex\n";
        }
        return std::visit(overload{
               [](const Complex& a, const Complex& b) -> Math_Object{ 
                   std::cerr << "COMPLEX ADD_\n"; 
                   return add_(a, b); 
               }
             , [](const Matrix& a, const Matrix& b) -> Math_Object{ 
                   std::cerr << "MATRIX ADD_\n"; 
                   return add_(a, b); 
               }
             , [&arg](auto& a, auto& b) -> Math_Node{
                   std::cerr << "NOT FOUND\n"; 
                   return arg;
             }
         }, obj1, obj2);
}

Код печатает

obj1 is complex
obj2 is complex
NOT FOUND

Это был рабочий код перед рефакторингом:

Math_Object Function_Manager::add(const Math_Object& arg0, const Math_Object& arg1){
        return
                std::visit(
                        overload{
                                [](const Complex& a, const Complex& b) -> Math_Object{ return add_(a, b); }
                                , [](const Matrix& a, const Matrix& b) -> Math_Object{ return add_(a, b); }
                                , [](auto& a, auto& b) -> Math_Object{
                                    throw std::runtime_error(
                                            ("Unsupported arguments for add: " + to_string(a) + to_string(b)).c_str());
                                }
                        }, arg0, arg1
                          );
    }

Единственное, что я мог придумать, это то, что obj1 и obj2 на самом деле не нужного типа, но печать std::cerr доказывает, что они есть. Так почему же std :: visit не распознает его как таковой и как я могу это исправить?

1 Ответ

3 голосов
/ 20 февраля 2020

В вашем первом примере obj1 и obj2 не квалифицированы const.

Во втором примере arg0 и arg1 являются.

overload просто выполняет разрешение перегрузки для операторов вызова всех лямбд, переданных ему (при условии, что это обычная реализация).


В разрешении перегрузки для первого примера auto& / auto& является лучшим соответствием для obj1 / obj2, чем const Complex& / const Complex&, поскольку для последнего требуется преобразование квалификации для добавления const, тогда как auto& / auto& может быть выведено в Complex& / Complex& , который не требует преобразования квалификации.


Во втором примере это не так, поскольку arg0 / arg1 равны const, вычет аргумента шаблона для auto& / auto& даст const Complex& / const Complex&, и ни этот вызов, ни тот, который принимает const Complex& / const Complex& напрямую, не потребуют каких-либо преобразований.

Если две функции имеют одинаково хорошие последовательности преобразования для вызова затем вызов устраняется по нескольким дополнительным критериям, один из которых В том, что не шаблонные функции предпочтительнее шаблонных функций. Перегрузка, принимающая const Complex& / const Complex& напрямую, не является шаблоном (поскольку она не является обобщенной c лямбда-выражением), и поэтому она предпочтительна.


Чтобы решить эту проблему, просто возьмите то же самое квалификации во всех вызовах, т. е. принимать const auto& / const auto& вместо auto& / auto& в последнем вызове или воспроизводить поведение разрешения перегрузки второго примера, передавая std::as_const(obj1) и std::as_const(obj2) вместо obj1 и obj2 до std::visit.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...