Я просто столкнулся с чем-то незаметным в непосредственной близости от std :: visit и std :: function, что сбивает меня с толку. Я не один, но единственные люди, которых я смог найти, танцевали «обходной путь и двигайся дальше», и этого для меня недостаточно:

Это может быть связано с открытой проблемой в LEG, но я думаю, что здесь происходит нечто более зловещее:

Минимальный пример:

// workaround 1: don't include <variant>
#include <variant>
#include <functional>

struct Target
{
  Target *next = nullptr;
};

struct Visitor
{
  void operator()(const Target &tt) const { }
};

// workaround 2: concretely use 'const Visitor &' instead of 'std::function<...>'
void visit(const Target &target, const std::function<void(const Target &)> &visitor)
{
  visitor(target);
  if(target.next)
    visit(*target.next,visitor); // workaround 3: explicitly invoke ::visit(...)
    //^^^ problem: compiler is trying to resolve this as std::visit(...)
}

int main(int argc, char **argv, char **envp)
{
  return 0;
}

Скомпилировать с g ++ -std = c ++ 17, протестировано с использованием:

  • g ++ - 7 (Ubuntu 7.5.0-3ubuntu1 ~ 18.04)
  • g ++ - 8 (Ubuntu 8.4.0-1ubuntu1 ~ 18.04)

В результате компилятор пытается использовать std :: visit для явно не-std вызова visit (* target.next, visitor):

g++-8 -std=c++17 -o wtvariant wtvariant.cpp
In file included from sneakyvisitor.cpp:3:
/usr/include/c++/8/variant: In instantiation of ‘constexpr decltype(auto) std::visit(_Visitor&&, _Variants&& ...) [with _Visitor = Target&; _Variants = {const std::function<void(const Target&)>&}]’:
wtvariant.cpp:20:31:   required from here
/usr/include/c++/8/variant:1385:23: error: ‘const class std::function<void(const Target&)>’ has no member named ‘valueless_by_exception’
       if ((__variants.valueless_by_exception() || ...))
            ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/8/variant:1390:17: error: no matching function for call to ‘get<0>(const std::function<void(const Target&)>&)’
      std::get<0>(std::forward<_Variants>(__variants))...));
      ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

В моем реальном случае использования я думал, что кто-то пробрал «using namespace std» в пространство заголовка моего дерева, и я был сварливым. Однако этот минимальный пример демонстрирует обратное.

Критический вопрос: учитывая, что я не создавал и не использовал никаких пространств имен, почему здесь вообще участвует std :: visit (...)?

  • Обходной путь WRT 1: по крайней мере, в заголовке варианта, visit (...) правильно объявлен в пространстве имен std
  • Обходной путь 2 WRT: если второй аргумент не является std :: function, он компилируется нормально, что наводит меня на мысль, что здесь происходит что-то более тонкое.
  • Обходной путь 3 WRT: я понимаю, что два двоеточия - небольшая плата, но то, что они вообще необходимы, кажется мне опасным, учитывая мои ожидания относительно того, что значит поместить бесплатную функцию, такую ​​как visit (...), в пространство имен.

Любой из трех отмеченных обходных путей подавит ошибку компилятора, но я лично не терплю языковых сбоев, которые я не могу осмыслить (хотя я понимаю необходимость, я все еще беспокоюсь о том, как часто мне нужно разбрызгивать 'typename' в шаблоны, чтобы они скомпилировались).

Также следует отметить, что если попытаться использовать другие элементы пространства имен std без квалификации (например, попробовать голый 'cout'), компилятор должным образом ворчит о том, что не может определить 'cout', который мне нужен, так что это не значит, что заголовок варианта каким-то образом сглаживает пространство имен std.

Наконец, эта проблема сохраняется, даже если я помещаю свой метод visit () в его собственное пространство имен: компилятор действительно хочет использовать std :: visit (...), если я явно не вызываю my_namespace :: visit (...).

Что мне не хватает?

8
Christopher Baker 15 Июн 2020 в 22:29

1 ответ

Лучший ответ

Аргумент visitor - это std::function, который находится в пространстве имен std, поэтому поиск по аргументу также находит visit в пространстве имен std.

Если вам всегда нужен visit в глобальном пространстве имен, скажите об этом с помощью ::visit.

4
Asteroids With Wings 15 Июн 2020 в 19:42