【问题标题】:ISO C++ standard conformant result of the following code以下代码符合 ISO C++ 标准的结果
【发布时间】:2012-02-22 14:12:18
【问题描述】:
#include <iostream>

template< typename U >
struct base {
    template< typename T >
    base const & operator<<( T x ) const {
        std::cout << sizeof( x ) << std::flush;
        return *this;
    }
};

template< typename U >
struct derived : public base< U > {
    using base<U>::operator<<;

    derived const & operator<<( float const & x ) const {
        std::cout << "derived" << std::flush;
        return *this;
    }
};

int main() {
    unsigned char c( 3 );
    derived< double > d;
    d << c;
    d.operator<<( c );
    return 0;
}

您能否解释一下获得上述代码正确答案所涉及的规则(与模板相关的重载和覆盖、积分提升……)?它有效吗?如果规则太长,请提供文献指针。最新的编译器不同意正确的结果。 gcc-4.6 和 icpc-12.1.0 声称“11”是正确答案,但 VS2010 由于含糊不清而拒绝编译 d &lt;&lt; c;,但接受 d.operator&lt;&lt;( c );。后者输出1iirc。那么谁对谁错呢?

【问题讨论】:

  • 嘿,有什么区别?如果 d &lt;&lt; c 不能在 MSVC 上编译,那么只有一个 1 可以打印。其他编译器打印两个1。还是我错过了什么?
  • 您需要意识到所涉及的任何数据类型都不会有 sizeof == 1: 8 可能,4 肯定,1 为什么不。但是 11 看起来真的很像两个 1
  • 你想要什么?试试编译器?
  • @J.N. c&lt;&lt;sizeof c == 1 的参数。如果程序无法编译,则不会打印任何内容。
  • 我猜问题是“为什么 MSVC 有编译器错误,而 gcc 没有,这是符合 ISO 的行为吗?”。老实说,我不知道这两个问题的答案。不过祝你好运。

标签: c++ visual-c++ g++ iso icc


【解决方案1】:

“11”是正确的输出。

对于这两个表达式,派生运算符

确切的规则很长。您可以在当前 C++ 草案标准的第 13.3 节 重载解决 中找到详细信息,n3337 链接到工作组文件的this list

如果你问为什么 MSVC 不编译一个语句,我不太确定,但是当有多个计算的 ICS 并不比彼此更好时,函数调用是模棱两可的(如 13.3. 3)。在d &lt;&lt; c 的情况下,MSVC 似乎为至少一个重载计算了错误的 ICS,但诊断没有提供更多细节:

error C2666: 'derived<U>::operator <<' : 2 overloads have similar conversions
      with
      [
          U=double
      ]
      ConsoleApplication1.cpp(24): could be 'const derived<U> &derived<U>::operator <<(const float &) const'
      with
      [
          U=double
      ]
      ConsoleApplication1.cpp(14): or       'const base<U> &base<U>::operator <<<unsigned char>(T) const'
      with
      [
          U=double,
          T=unsigned char
      ]
      while trying to match the argument list '(derived<U>, unsigned char)'
      with
      [
          U=double
      ]

【讨论】:

  • 我相信你是对的。我认为微妙之处在于 C++ 想要选择非模板函数而不是模板函数,而且还想要选择更好的转换顺序。在这种情况下,模板的转换顺序更好。 13.3.3.1 显示了非模板函数何时被认为比模板函数更好,并且仅适用于非模板函数没有更差的转换序列时。但是,在这种情况下,非模板函数的转换顺序确实更差。
【解决方案2】:

它无法编译,因为您要求自动调用 operator &lt;&lt;。这就像拥有operator +,以及拥有可以转换为基本类型的转换运算符(例如,转换为int)。例如:

class Conversion
{
public:
    operator int()
    {
        return 5;
    }

    int operator +(int x)
    {
        return 10;
    }
};

并像这样使用它:

Conversion conv;
conv + 1.0;

这里operator + 不能被隐式调用,因为operator int 也是可能的。如果你通过了,int,但是,operator +(int) 将被调用。要使用 double 调用 operator+,我们可以这样做:

conv.operator+(1.0);

我不知道编译器规则和严格的标准定义。

我还发现,如果我们将 basederived 类更改为非模板类​​,问题仍然存在(在 VC10/11 中):

struct base {   
    base const & operator<<( int x ) const { 
        std::cout << sizeof( x ) << std::flush; 
        return *this; 
    } 
}; 

struct derived : public base{ 
    using base::operator<<; 
    derived const & operator<<( float const & x ) const { 
        std::cout << "derived" << std::flush; 
        return *this; 
    } 
}; 

int main()
{
  derived d;
  d<<10.0;  // ERROR
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-22
    • 2011-09-08
    相关资源
    最近更新 更多