实例化隐藏功能

Dim*_*imG 0 c++ c++11

Condider以下代码:

template <class Impl, class Cont>
struct CrtpBase
{
    void foo()
    {
        cout << "Default foo\n";
        Cont cont;
        cont.push_back(10); // Going to fail if Cont::push_back doesn't exist
    }
};

typedef std::unordered_map<int,int> ContType;
struct Child : public CrtpBase<Child, ContType>
{
    typedef CrtpBase<Child, ContType> _Parent;
    // using _Parent::foo // (1)
    void foo() { cout << "Child\n"; }
};

int main()
{
    Child obj;
    obj.foo(); // (2)
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我坚持的是CrtpBase类被实例化时的条件,而不是.

在第(2)点,当我调用时 foo(),从我的观点来看,编译器应该生成一个可能的重载列表.这些是Child::foo()Child::_Parent::foo().因此Child::_Parent::foo()必须实例化.(此时编译应该失败,因为错误在body函数中,SFINAE不适用)然后编译器应该选择优先级匹配.

但是程序编译并显示CrtpBase::foo未实例化.问题是为什么.编译器以某种方式知道这Child::foo将是最佳匹配并停止重载解析过程.

当我取消注释时// using ...,要求编译器明确地使用基函数重载作为匹配之一,没有任何改变,它再次编译

只是从下面的答案中得出我所理解的结论,因为它们涵盖了正在发生的事情的不同方面

  1. 编译器甚至不考虑基本重载.这是我没有看到的关键事实,因此也是所有的误解

  2. 这不是这种情况,但在重载决策期间选择最佳匹配仅实例化所选匹配

Bar*_*rry 5

在第(2)点,当我调用foo()时,在我看来,编译器应该生成一个可能的重载列表.

Trueish.我们通过查找名字开始fooChild.我们找到Child::foo然后停下来.我们只有一个候选人,这是一个可行的候选人,所以我们称之为.我们不会继续查看基类,因此CrtpBase::foo从未考虑过.无论签名如何(如果CrtpBase::foo()采用a int,obj.foo(4)将无法编译,因为Child::foo()不进行参数 - 即使假设的调用CrtpBase::foo(4)将很好地形成)也是如此.

当我取消注释时// using ...,要求编译器明确地使用基函数重载作为匹配之一,没有任何改变,它再次编译

那实际上并不是你在做什么.在using声明带来的名字CrtpBase::foo进入的范围Child,就好像它被宣布那里.但随后声明void foo()重载的隐藏(否则调用将是模糊的).再次,fooChild查找Child::foo和停止中查找名称.当这种情况不同于以前的情况是,如果CrtpBase::foo()采取了不同的参数,那么它被视为(比如我hyptohetical obj.foo(4)在上一段通话).