13

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

#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 studio

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 上编译得很好(并且表现也符合预期)。

经过一些额外的测试,我发现如果我在派生中避免使用 CRTP 模式,代码编译得很好DerivedState

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

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

4

1 回答 1

7

根据cppreference 文档(重点是我的)

使用声明将基类的成员引入派生类定义中,例如将基类的受保护成员公开为派生的公共成员。在这种情况下,nested-name-specifier 必须命名一个被定义的基类。如果名称是基类的重载成员函数的名称,则引入具有该名称的所有基类成员函数。如果派生类已经有一个具有相同名称、参数列表和限定条件的成员,则派生类成员隐藏或覆盖(不与)从基类引入的成员。

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

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

于 2017-07-12T12:16:56.907 回答