ISO C++以下代码的标准一致结果

发布于 2025-01-07 20:39:20 字数 936 浏览 2 评论 0原文

#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 << c; 由于不明确,但接受 d.operator<<( c );。后者输出 1 iirc。那么谁是对的,谁是错的呢?

#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;
}

Can you please explain the rules involved to obtain a correct answer of the above code (overloading and overriding in connection with templates, integral promotion, ...)? Is it valid? If the rules are too lengthy please provide literature pointers. The latest compilers disagree about the correct result. gcc-4.6 and icpc-12.1.0 claim "11" is the correct answer but VS2010 refuses to compile d << c; due to ambiguities but accepts d.operator<<( c );. The latter outputs 1 iirc. So who's right and who's wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

风柔一江水 2025-01-14 20:39:20

“11”是正确的输出。

对于这两个表达式,派生运算符<<都是和基运算符<<是候选人。然后根据候选者所需的隐式转换序列对候选者进行比较。因为基运算符<<是一个模板函数,其中类型 T 已被推导为与参数匹配,在这两种情况下它都是更好的匹配。

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

如果您问为什么 MSVC 不编译一条语句,我不太确定,但是当存在多个彼此不更好的计算 ICS 时,函数调用是不明确的(如 13.3.3 中定义)。在 d << 的情况下,MSVC 似乎为至少一个重载计算了错误的 ICS。 c,但诊断没有提供更多详细信息:

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
      ]

"11" is the correct output.

For both expressions both the derived operator<< and base operator<< are candidates. Then the candidates are compared based on the implicit conversion sequences they require. Because the base operator<< is a template function where the type T has been deduced to match the argument it comes up as the better match in both cases.

The exact rules are pretty long. You can find the details in section 13.3 Overload resolution of the current C++ draft standard, n3337 linked to in this list of the working group's papers.

If you're asking why MSVC doesn't compile the one statement, I'm not exactly sure, but a function call is ambiguous when there are multiple computed ICSs that are not better than each other (as defined in 13.3.3). MSVC seems to be computing the wrong ICS for at least one of the overloads in the case of d << c, but the diagnostic doesn't give any more details:

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
      ]
掐死时间 2025-01-14 20:39:20

它不会编译,因为您要求自动调用 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);

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

我还发现,如果我们将基类和派生类更改为非模板类​​,问题仍然存在(在 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
}

It doesn't compile because you are asking operator << to be invoked automatically. It is like having operator +, as well as having conversion operator that can convert to basic type (say, to int). For example:

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

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

And using it like:

Conversion conv;
conv + 1.0;

Here operator + cannot be implicitly invoked, since operator int is also possible. If you pass, int, however, operator +(int) will be called. To invoke operator+ with double, we can do:

conv.operator+(1.0);

I don't know about the compiler rules, and the strict standards definition.

I also found out, that if we change the base and derived classes as non-template classes, the problem would still remain (in 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
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文