首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >调用非成员函数而不是成员函数

调用非成员函数而不是成员函数
EN

Stack Overflow用户
提问于 2012-11-15 22:16:13
回答 3查看 4.7K关注 0票数 14

我有一个非常简单的问题:某个地方有一个函数

代码语言:javascript
运行
复制
int size (const C & c)

它至少是通过依赖于参数的名称查找找到的。现在的问题是:

代码语言:javascript
运行
复制
struct B
{
    int size () { /* ... */ }

    void doSomething (const C & c)
    {
       int x = size (c); // <----------- problem!
       // ...
    }
}

这不起作用,因为在找到成员函数之后,名称查找就停止了。

如果不尝试调用成员函数,而是编译器执行如果成员函数不存在的话,那么我必须在指定的行中写入什么呢?

请注意,该解决方案并不是编写::size,因为这样可以防止参数依赖的名称查找,并且只有当我知道size在哪里声明时才能工作。

进一步并发症:

我知道,对于我使用以下模板成员函数B::doSomething的每个相关类型的B::doSomething,都会有一个函数

代码语言:javascript
运行
复制
int size (const T & t)

它至少是通过依赖于参数的名称查找找到的。B看起来如下:

代码语言:javascript
运行
复制
struct B
{
    int size () { /* ... */ }

    template<class T>
    void doSomething (const T & t)
    {
       int x = size (t); // <----------- problem!
       // ...
    }
}

我希望调用非会员函数(我确信它存在,但我不能确定它在哪里)。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-08-19 09:15:25

这是一个众所周知的问题,它的解决办法也是众所周知的.我很惊讶这件事还没被提起。如果您有一个非成员函数,如下所示:

代码语言:javascript
运行
复制
class C;
size_t size( C const &c );

您可以使用using声明比成员函数更好地查找名称:

代码语言:javascript
运行
复制
struct B {
  size_t size();

  void foo( C const &c ) {
    using ::size;
    size_t sz = size(c);
  }
};

当编译器看到对size(c)的调用时,它从最内部的作用域开始,并向外搜索名为size的内容。如果没有using声明,编译器就会在全局命名空间中的非成员之前在类范围内找到成员函数,但是using声明会改变这一点。最内部的作用域是函数本身,使用声明在成员函数之前找到。

这样做的好处是,您仍然可以获得依赖于参数的查找(ADL),因为对size(c)的实际调用是不合格的。这意味着您可以在模板中使用它:

代码语言:javascript
运行
复制
template <class T>
void foo( T const &c ) {
  using ::size;
  size_t sz = size(c);
}

..。即使正确的size函数位于另一个名称空间中,它也会被ADL找到。using声明只需要引用一些size函数,而不一定是您真正想要的函数。正常情况下,在某个地方有一个可能调用该成员的默认实现。下一个版本的C++标准(C++17)几乎肯定会有一个std::size函数来实现这一点。一旦它被广泛使用,你就可以写

代码语言:javascript
运行
复制
using std::size;
size_t sz = size(c);

目前,您可以提供自己的默认实现,如下所示:

代码语言:javascript
运行
复制
template <class C>
constexpr auto size( C const &c ) -> decltype(c.size()) {
  return c.size();
}

..。或者您可以继续引用C的版本,并依赖于ADL找到正确的版本。

票数 15
EN

Stack Overflow用户

发布于 2012-11-15 22:19:07

如果不能重命名自己的成员函数,则可以使用一个肮脏的技巧:

代码语言:javascript
运行
复制
static inline int dirty_trick(C const & c)
{
    return size(c);
}

void B::doSomething(C const & c)
{
    int x = dirty_trick(c);

    // ...
}
票数 6
EN

Stack Overflow用户

发布于 2015-08-20 19:50:57

为了完整,并在Richard Smith所接受的答案中添加了以下内容:

我现在的解决方案如下:

代码语言:javascript
运行
复制
namespace adl {
   // This declaration's only purpose is the possibility to refer to
   // a non-member function named "size" in a using declaration.
   //
   // The signature does not matter, so we choose the easiest possible one.
   void size ();
}

struct B
{
    int size () { /* ... */ }

    template<class T>
    void doSomething (const T & t)
    {
       using adl::size;
       int x = size (t); // <----------- no problem anymore
       // ...
    }
};

这样,我就不必包含任何可能实际上不需要的标题。

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

https://stackoverflow.com/questions/13407205

复制
相关文章

相似问题

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