为什么此 C++ 代码仅在 Microsoft 编译器上有模棱两可的方法调用?

Why has this C++ code an ambiguous method call only on Microsoft compiler?

我正在尝试在 Microsoft C++ 编译器 14.1(Visual Studio 2017)上编译一个库,但由于对 class 方法的调用不明确,我遇到了一个奇怪的错误。 经过一些测试后,我分离出以下代码片段:

#include <iostream>

struct Event
{};

template<typename Derived>
struct State
{
public:
    template<typename Fsm>
    void onEvent(Fsm& fsm, const Event& event)
    {
        std::cout << "State::onEvent\n";
    }

};

struct DerivedState
    : State<DerivedState>
{
public:
    using State::onEvent;

    template<typename Fsm>
    void onEvent(Fsm& fsm, const Event& event)
    {
        std::cout << "DerivedState::onEvent\n";
    }

};

struct Context
{};


int main()
{
    DerivedState ds;
    Context context;
    ds.onEvent(context, Event());
}

我得到以下输出:

1>c:\users\pmas\documents\visual 工作室

2017\projects\consoleapplication3\consoleapplication3\consoleapplication3.cpp(87): error C2668: 'DerivedState::onEvent': ambiguous call to overloaded function
1>c:\users\pmas\documents\visual studio 2017\projects\consoleapplication3\consoleapplication3\consoleapplication3.cpp(59): note: could be 'void DerivedState::onEvent<Context>(Fsm &,const Event &)'
1>        with
1>        [
1>            Fsm=Context
1>        ]
1>c:\users\pmas\documents\visual studio 2017\projects\consoleapplication3\consoleapplication3\consoleapplication3.cpp(45): note: or       'void State<DerivedState>::onEvent<Context>(Fsm &,const Event &)'
1>        with
1>        [
1>            Fsm=Context
1>        ]
1>c:\users\pmas\documents\visual studio 2017\projects\consoleapplication3\consoleapplication3\consoleapplication3.cpp(87): note: while trying to match the argument list '(Context, Event)'

代码在我看来完全合法并且在 gcc、clang 和 icc 上编译良好(并且表现也符合预期)。

经过一些额外的测试,我发现如果我在推导 DerivedState:

时避免使用 CRTP 模式,代码可以正常编译
#include <iostream>

struct Event
{};

struct State
{
public:
    template<typename Fsm>
    void onEvent(Fsm& fsm, const Event& event)
    {
        std::cout << "State::onEvent\n";
    }

};

struct DerivedState
    : State
{
public:
    using State::onEvent;

    template<typename Fsm>
    void onEvent(Fsm& fsm, const Event& event)
    {
        std::cout << "DerivedState::onEvent\n";
    }

};

struct Context
{};


int main()
{
    DerivedState ds;
    Context context;
    ds.onEvent(context, Event());
}

任何人都可以解释这种差异吗?微软编译器是不是不符合标准?

根据 cppreference documentation(强调我的)

Using-declaration introduces a member of a base class into the derived class definition, such as to expose a protected member of base as public member of derived. In this case, nested-name-specifier must name a base class of the one being defined. If the name is the name of an overloaded member function of the base class, all base class member functions with that name are introduced. If the derived class already has a member with the same name, parameter list, and qualifications, the derived class member hides or overrides (doesn't conflict with) the member that is introduced from the base class.

所以基本上您对该方法的 using 声明并没有真正做任何事情(无论如何该方法是 public,所以不需要 using)。您派生的 class 只是 隐藏了 onEvent 方法。

所以其他编译器是对的,微软是错的。