Zeldhoron
Zeldhoron

Reputation: 69

C++ MSVC/GCC/Clang compilers bug

I discovered what appears to be a mind breaking bug in the 3 compilers from the title. The following code compiles with the latest versions of all three compilers using both the c++11 and c++14 standards, even though it really shouldn't as the "visit_detail" function is not visible to "main".

Correction: I was stupid, not actually a bug in GCC/Clang, seems to be a bug in my MSVC version tho.

#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;
}

Upvotes: 2

Views: 277

Answers (1)

Vittorio Romeo
Vittorio Romeo

Reputation: 93274

What you're experiencing is a C++ feature called argument-dependent lookup, or ADL for short. Basically, if you invoke a function f without explicitly qualifying it, the compiler will look for f in the namespaces of the arguments that you've passed.

This is what allows operator<< for IO streams to work without requiring qualifications:

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

In your particular case, the argument bug::detail::visit_stop is making the compiler look for visit_detail inside the bug::detail namespace.

Upvotes: 5

Related Questions