Chr*_*ker 8 c++ g++ visitor variant c++17
我只是在 std::visit 和 std::function 附近反弹到一些微妙的东西,这让我感到困惑。我并不孤单,但我能找到的唯一其他人做了“解决方法并继续前进”的舞蹈,这对我来说还不够:
这可能与 LWG 中的一个悬而未决的问题有关,但我认为这里正在发生一些更险恶的事情:
最小示例:
// workaround 1: don't include <variant>
#include <variant>
#include <functional>
struct Target
{
Target *next = nullptr;
};
struct Visitor
{
void operator()(const Target &tt) const { }
};
// workaround 2: concretely use 'const Visitor &' instead of 'std::function<...>'
void visit(const Target &target, const std::function<void(const Target &)> &visitor)
{
visitor(target);
if(target.next)
visit(*target.next,visitor); // workaround 3: explicitly invoke ::visit(...)
//^^^ problem: compiler is trying to resolve this as std::visit(...)
}
int main(int argc, char **argv, char **envp)
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
用 g++ -std=c++17 编译,测试使用:
最终结果是编译器尝试使用 std::visit 来调用显然不是 std 的 visit(*target.next,visitor):
g++-8 -std=c++17 -o wtvariant wtvariant.cpp
In file included from sneakyvisitor.cpp:3:
/usr/include/c++/8/variant: In instantiation of ‘constexpr decltype(auto) std::visit(_Visitor&&, _Variants&& ...) [with _Visitor = Target&; _Variants = {const std::function<void(const Target&)>&}]’:
wtvariant.cpp:20:31: required from here
/usr/include/c++/8/variant:1385:23: error: ‘const class std::function<void(const Target&)>’ has no member named ‘valueless_by_exception’
if ((__variants.valueless_by_exception() || ...))
~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/8/variant:1390:17: error: no matching function for call to ‘get<0>(const std::function<void(const Target&)>&)’
std::get<0>(std::forward<_Variants>(__variants))...));
~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)
在我的实际用例中,我认为有人在我的树的标题空间中偷偷地添加了一个“使用命名空间 std”,我会变得脾气暴躁。然而,这个最小的例子展示了另外的情况。
关键问题:鉴于我没有创建或使用任何命名空间,为什么 std::visit(...) 会参与其中?
Any one of the three marked workarounds will suppress the compiler error, but I'm personally intolerant of language glitches that I can't wrap my head around (Though I understand the necessity, I'm still uneasy about how often I have to sprinkle 'typename' into templates to make them compile).
Also of note, if try to make use of other elements of the std namespace without qualification (e.g., try a naked 'cout'), the compiler properly grumps about not being able to figure out the 'cout' that I'm after, so it's not as though the variant header is somehow flattening the std namespace.
Lastly, this problem persists even if I put my visit() method in its own namespace: the compiler really wants to use std::visit(...) unless I explicitly invoke my_namespace::visit(...).
What am I missing?