代码之家  ›  专栏  ›  技术社区  ›  Steve314

如何解决重载成员函数问题的这个地址?

  •  0
  • Steve314  · 技术社区  · 15 年前

    [ 编辑 -我早就忘了这是在这里,直到我得到2500个意见“值得注意的问题”。因为人们正在查看-在接受的答案中有关于重载的有用信息,但特别是检查 std::endl 比我当时意识到的还要糟,而且肯定是错的。

    基本上,影响 STD::Endol 是输出 \n 到小溪,然后冲洗 std::flush . 这与平台无关,包括行尾实际为“r\n”的窗口。这个 endl 机械手不会抽象平台差异WRT线结束,C++处理与C相同的方式-通过翻译 \n 到\r\n(对于文本模式,不是二进制)以后。我认为C++做了一些不同的事情,一个假设如此强烈,我甚至从来没有质疑过它2年,但我错了。

    我不记得细节,但无论如何都可以定义自己的流,并提供任何字符的可选输出(和翻译)。所有机械手应按预期工作, 之前 您的自定义流代码可以看到生成的输出字符。因此,要提供特殊的行尾行为,请注意 \n 存在(仍在文本文件行末转换之前)。 ]

    我知道,这是一种黑客行为,但最近我需要实现一个流类,它的作用主要类似于标准流,但它可以检测std::endl操纵器和特殊情况下的行为。我第一次尝试实现特定的方法是…

    mystream& mystream::operator<< (std::basic_ostream<char>& (*p) (std::basic_ostream<char>&))
    {
      if (p == &std::endl)
      {
        //  Handle special case
      }
      else
      {
        m_Underlying_Stream << p;
      }
    
      return *this;
    }
    

    问题在于编译器不知道哪个重载 STD::Endol 我指的是。我决定如下…

    mystream& mystream::operator<< (std::basic_ostream<char>& (*p) (std::basic_ostream<char>&))
    {
      typedef std::basic_ostream<char>& (*ENDL_T) (std::basic_ostream<char>&);
    
      const ENDL_T l_ENDL (&std::endl);
    
      if (p == l_ENDL)
      {
        //  Handle special case
      }
      else
      {
        m_Underlying_Stream << p;
      }
    
      return *this;
    }
    

    也就是说,编译器可以在初始化上下文中解决重载问题(正如另一个实验所证明的那样,对于赋值也是如此),但对于 operator== .

    有问题的编译器是mingwGCC4.4.0,但我不认为这可能是编译器的问题。

    我环顾四周发现了这个问题…

    How to get the address of an overloaded member function?

    如果我的代码有一个常量问题,我不知道丢失的常量需要去哪里。我看不到任何其他明显的类型问题。

    我对步骤的数量有一些模糊的想法,比如过载或隐式铸造,但没有具体的想法。任何人都能清楚地解释我的第一个例子有什么问题,为什么第二个版本会修复它,以及我如何安全地指出在获取函数地址时我的意思是哪个重载。

    顺便说一句,我猜有些人不喜欢我直接测试的地址 STD::Endol 并将指出这是脆弱的-例如,有人可能有自己的操纵器调用 STD::Endol 我不会发现的。一般来说,这是真的,但在这个特殊的情况下,黑客节省了很多时间,而这种肮脏并不重要。

    3 回复  |  直到 8 年前
        1
  •  2
  •   CB Bailey    15 年前

    只有在一组有限的上下文中才允许使用无参数的重载函数名(或行为类似于一组重载函数的函数模板的名称)(例如在“地址”表达式中),上下文可用于唯一确定所需的特定重载。

    这在本标准(ISO/IEC 14882:2003)的13.4中有规定[以上]。包含的是对象、引用或显式转换的初始值设定项。这为您提供了许多选项。

    例如,显式转换:

    typedef std::ostream& (*ManipPtr)(std::ostream&);
    
    mystream& mystream::operator<<(ManipPtr p)
    {
        if (p == static_cast<ManipPtr>(&std::endl))
        {
            // ...
    

    直接初始化指针:

    typedef std::ostream& (*ManipPtr)(std::ostream&);
    
    mystream& mystream::operator<<(ManipPtr p)
    {
        const ManipPtr pEndl = &std::endl;
    
        if (p == pEndl)
        {
            // ...
    
        2
  •  1
  •   Cubbi    15 年前

    以下工作:

    #include <iostream>
    
    struct mystream {
        typedef std::basic_ostream<char>& (*ENDL_T) (std::basic_ostream<char>&);
        mystream& operator<< (ENDL_T p)
        {
            if (p == (ENDL_T)std::endl)
            {
                std::cout << "special case\n";
            }
            else
            {
                std::cout << "usual case\n";
            }
            return *this;
        }
    };
    
    int main()
    {
        mystream ms;
        ms << std::endl; // prints "special case"
        ms << std::flush; // prints "usual case"
    }
    
        3
  •  0
  •   Mike Caron    15 年前

    它不能区分重载的原因是您解析了函数的地址,而不是调用它。当您在流中插入它时,编译器知道调用 endl(ostream&) 超载。除此之外,你是自己的。

    为什么不直接测试'\n'呢?