【问题标题】:C++ MSVC/GCC/Clang compilers bugC++ MSVC/GCC/Clang 编译器错误
【发布时间】:2017-10-17 02:48:59
【问题描述】:

我从标题中发现了 3 个编译器中似乎是一个令人难以置信的错误。以下代码使用 c++11 和 c++14 标准与所有三个编译器的最新版本一起编译,尽管它确实不应该,因为 "visit_detail" 函数对 "main" 不可见。

更正:我很愚蠢,实际上不是 GCC/Clang 中的错误,但似乎是我的 MSVC 版本中的错误。

#include <utility>
#include <iostream>
#include <type_traits>



namespace bug
{
    using namespace std;
    using size_t = unsigned long long;



    namespace detail
    {
        struct visit_stop_t {};
        constexpr bug::detail::visit_stop_t visit_stop = bug::detail::visit_stop_t();



        template <typename Visitor, typename First, typename... Tail>
        void visit_detail(Visitor&& vis, First&& first, Tail&&... tail)
        {
            // code, not necessairy to recreate bug
        }
    }


    template <typename Visitor, typename... Variants>
    void visit(Visitor&& vis, Variants&&... vars)
    {
        bug::detail::visit_detail(bug::forward<Visitor>(vis), bug::forward<Variants>(vars)..., bug::detail::visit_stop);
    }

    template <typename Visitor>
    void visit(Visitor&& vis) = delete;
}

using namespace bug;



// dummy variant, used to test the code
// code is never actually used in this version
template <typename... T>
struct variant
{
    static constexpr bug::size_t size() noexcept { return sizeof...(T); }


    constexpr variant(int) noexcept {}

    template <bug::size_t I>
    constexpr int get() const noexcept { return 5; }
};

// simple example visitor
// code is never actually used in this version
struct visitor
{
    int operator()(int x) { std::cout << x << std::endl; return x; }
    double operator()(double x) { std::cout << x << std::endl; return x; }
};



int main()
{
    visitor vis;
    variant<int, double> var = 5;

    // where the trouble is:
    visit_detail(vis, var, bug::detail::visit_stop);  // ADL: http://en.cppreference.com/w/cpp/language/adl
    visit_detail(vis, var);  // fails with GCC/Clang, no error with MSVC => MSVC bug maybe


    std::cout << "Press enter to continue . . . ";
    std::getchar();
    return 0;
}

【问题讨论】:

  • 我怀疑您看到的是 ADL 的实际应用
  • using size_t = unsigned long long; 为什么?为什么?至少做using size_t = decltype(sizeof(int));之类的事情,或者更好的是,包括&lt;cstddef&gt;
  • 这只是一些快速而肮脏的代码示例,我将它们放在一起以显示错误实际上是什么
  • 正如 Andrey 所说,这是 argument-dependent lookup,而不是错误。
  • 很确定使用bug::detail::visit_stop 会将bud::detail::visit_detail 带入作用域,因为参数也在同一个命名空间内。

标签: c++ c++11 gcc visual-c++ clang


【解决方案1】:

您正在体验的是一个名为 argument-dependent lookup 或简称 ADL 的 C++ 功能。基本上,如果您调用函数 f 而不明确限定它,编译器将在您传递的参数的命名空间中查找 f

这就是让operator&lt;&lt; IO 流无需资格即可工作的原因:

std::cout << 100; // finds std::operator<<(std::ostream&, int);

在您的特定情况下,参数bug::detail::visit_stop 使编译器在bug::detail 命名空间内查找visit_detail

【讨论】:

  • 刚刚更新了帖子,“main”中的“visit_detail(vis, arg)”也适用于msvc
  • @Zeldhoron 刚刚在 gcc.godbolt.com 上测试过,GCC 和 Clang 都拒绝了第二行。
  • 是的,也和他们一起测试过,同样的,所以是 MSVC 错误
  • @Zeldhoron 您在使用什么 MSVS?它无法为我编译。
  • idk,我使用的是最新的 Visual Studio 2017 版本,目前正在尝试查找 vc++ 编译器的实际版本号
猜你喜欢
  • 2011-07-16
  • 2020-06-03
  • 1970-01-01
  • 2023-03-15
  • 2023-01-13
  • 2010-10-18
  • 2020-05-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多