C++ MSVC/GCC/Clang编译器错误

Zel*_*ron 2 c++ gcc clang visual-c++ c++11

我从标题中发现了3个编译器中看起来像是一个令人头疼的错误.下面的代码使用c ++ 11和c ++ 14标准编译所有三个编译器的最新版本,即使它真的不应该因为"main"看不到"visit_detail"函数.

更正:我是愚蠢的,实际上并不是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;
}
Run Code Online (Sandbox Code Playgroud)

Vit*_*meo 5

您所遇到的是一个C++特性,称为依赖于参数的查找,或简称为ADL.基本上,如果在f没有显式限定函数的情况下调用函数,编译器将f在您传递的参数的名称空间中查找.

这使得operator<<IO流无需资格即可工作:

std::cout << 100; // finds std::operator<<(std::ostream&, int);
Run Code Online (Sandbox Code Playgroud)

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