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

时间:2017-05-17 14:51:34

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

我在标题的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;
}

1 个答案:

答案 0 :(得分:5)

您正在体验的是名为argument-dependent lookup的C ++功能,或简称ADL。基本上,如果在没有明确限定函数的情况下调用函数f,编译器将在您已经传递的参数的名称空间中查找f

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

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

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