c++ - g++ std::visit 泄漏到全局命名空间?

标签 c++ g++ c++17 variant visitor

我只是在 std::visit 和 std::function 附近反弹到一些微妙的东西,这让我感到困惑。我并不孤单,但我能找到的唯一其他人做了“解决方法并继续前进”的舞蹈,这对我来说还不够:

  • https://github.com/fmtlib/fmt/issues/851
  • https://github.com/jamboree/bustache/issues/11

  • 这可能与 LWG 中的一个悬而未决的问题有关,但我认为这里正在发生一些更险恶的事情:
  • https://cplusplus.github.io/LWG/issue3052

  • 最小示例:
    // 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))...));
          ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    

    在我的实际用例中,我认为有人在我的树的标题空间中偷偷地添加了一个“使用命名空间 std”,我会变得脾气暴躁。然而,这个最小的例子展示了另外的情况。

    关键问题:鉴于我没有创建或使用任何命名空间,为什么 std::visit(...) 会参与其中?
  • WRT 解决方法 1:至少在变体 header 中,visit(...) 在 std 命名空间中正确声明
  • WRT 解决方法 2:如果第二个参数不是 std::function,它编译得很好,让我相信这里发生了一些更微妙的事情。
  • WRT 解决方法 3:我知道两个冒号是一个很小的代价,但是鉴于我对将诸如访问(...)之类的免费函数放入命名空间意味着什么的期望,它们是必要的,这对我来说是危险的。

  • 三种标记的解决方法中的任何一种都会抑制编译器错误,但我个人无法容忍我无法解决的语言故障(虽然我理解必要性,但我仍然对我必须多久洒一次感到不安'typename' 到模板中以使它们编译)。

    另外值得注意的是,如果尝试不加限定地使用 std 命名空间的其他元素(例如,尝试一个裸的“cout”),编译器就会提示无法找出我所追求的“cout”,所以这并不是说变体 header 以某种方式扁平化了 std 命名空间。

    最后,即使我把我的visit() 方法放在它自己的命名空间中,这个问题仍然存在:除非我显式调用my_namespace::visit(...),否则编译器真的想使用std::visit(...)。

    我错过了什么?

    最佳答案

    参数 visitorstd::function ,它在命名空间 std 中,所以 argument-dependent lookup发现 visit在命名空间 std以及。

    如果您总是想要 visit在全局命名空间中,用 ::visit 这么说.

    关于c++ - g++ std::visit 泄漏到全局命名空间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62395578/

    相关文章:

    c++ - SQL Server Compact Edition 3.5 为简单查询提供 "Multiple-step operation generated errors"错误

    c++ - 如何使用 PyBind 将 Python 嵌入到 C++ 中,而不是使用 CMake?

    c++ - 速度 : typedef vs #define in c++

    c++ - 为什么 std::enable_if 需要第二种模板类型?

    c++ - 使用默认模板参数推导模板参数失败

    c++ - 类返回 Rcpp::Vector<RTYPE> 元素的模板

    c++ - 有效或无效的迭代器和迭代器位置

    c++ - 如何避免在模板函数中使用浮点文字缩小转换

    c++ - 编译基本 C++ 类

    c++ - `static_assert` 如何在成员初始值设定项列表中构造模板类?