首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >隐函数的实例化

隐函数的实例化
EN

Stack Overflow用户
提问于 2016-10-06 13:52:47
回答 2查看 61关注 0票数 0

编写以下代码:

代码语言:javascript
运行
复制
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;
}

我所坚持的是CrtpBase类实例化和不实例化的条件。

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

但是,该程序编译并显示CrtpBase::foo没有实例化。问题是为什么。编译器不知何故知道Child::foo将是最佳匹配,并停止过载解析过程。

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

只是想总结一下我从下面的答案中了解到的,因为它们涵盖了的不同方面

  1. 编译器甚至不考虑基重载。这是我没有看到的关键事实,所以所有的误解
  2. 这里不是这样的,但是在重载解析中选择最佳匹配只实例化所选的匹配。
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-10-06 14:06:42

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

真有道理。我们首先在foo中查找Child的名称。我们找到Child::foo然后停下来。我们只有一个候选人,这是一个可行的候选人,所以我们称之为。我们不再继续查看基类,因此从未考虑过CrtpBase::foo。不管签名如何,这都是正确的(如果CrtpBase::foo()使用intobj.foo(4)将无法编译,因为Child::foo()不带参数--即使对CrtpBase::foo(4)的假设调用格式很好)。

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

这其实不是你要做的。using-声明将名称CrtpBase::foo带入Child的作用域,就好像它是在那里声明的一样。但是,void foo()的声明隐藏了该重载(否则调用将是模糊的)。因此,fooChild中的名称查找会发现Child::foo并停止。与前一种情况不同的是,如果CrtpBase::foo()采用了不同的参数,那么就会考虑它(比如上一段中我的obj.foo(4)调用)。

票数 5
EN

Stack Overflow用户

发布于 2016-10-06 14:06:01

模板类实例可以在不实例化其方法的情况下实例化。

Child不是模板类实例。它的方法总是被实例化。

简单地对模板类实例方法名称执行重载解析不会触发模板类方法实例化。如果没有选择它,就不会实例化它。

这个特性最初是在C++的历史前添加的。它允许std::vector<T>有一个有条件地工作的operator<,这取决于T在SFINAE前的C++时代是否有operator<

就更简单的情况而言:

代码语言:javascript
运行
复制
template<class T>
struct hello {
    void foo() { T t{}; t -= 2; }
    void foo(std::string c) { T t{}; t += c; }
};

实例化

调用hello<int>.foo()会考虑hello::foo(std::string),而不会实例化它。

调用hello<std::string>.foo("world");会考虑hello::foo(),而不会实例化它。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39897877

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档