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