c++ - 为什么这里会出现这种歧义?

标签 c++ templates operator-overloading

考虑我有以下最少的代码:

#include <boost/type_traits.hpp>

template<typename ptr_t>
struct TData
{
    typedef typename boost::remove_extent<ptr_t>::type value_type;
    ptr_t data;

    value_type & operator [] ( size_t id ) { return data[id]; }
    operator ptr_t & () { return data; }
};

int main( int argc, char ** argv )
{
    TData<float[100][100]> t;   
    t[1][1] = 5;
    return 0;
}

GNU C++ 给了我错误:

test.cpp: In function 'int main(int, char**)':
test.cpp:16: error: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for second:
test.cpp:9: note: candidate 1: typename boost::remove_extent<ptr_t>::type& TData<ptr_t>::operator[](size_t) [with ptr_t = float [100][100]]
test.cpp:16: note: candidate 2: operator[](float (*)[100], int) <built-in>

我的问题是:

  1. 为什么 GNU C++ 给出错误,而 Intel C++ 编译器却没有?
  2. 为什么把 operator[] 改成下面这样会导致编译没有错误?

    value_type & operator [] ( int id ) { return data[id]; }

感谢 C++ 标准的链接。


我可以看到这里有两种转化路径:

  1. (1)intsize_t 和 (2)operator[](size_t)
  2. (1)operator ptr_t&(),(2)intsize_t 和 (3)内置 operator[ ](size_t).

最佳答案

其实很简单。对于t[1] , 重载决议有以下候选:

候选 1(内置:13.6/13)(T 是任意对象类型):

  • 参数列表:(T*, ptrdiff_t)

候选人 2(您的接线员)

  • 参数列表:(TData<float[100][100]>&, something unsigned)

参数列表由 13.3.1.2/6 给出:

The set of candidate functions for overload resolution is the union of the member candidates, the non-member candidates, and the built-in candidates. The argument list contains all of the operands of the operator.

  • 参数列表:(TData<float[100][100]>, int)

您看到第一个参数与候选 2 的第一个参数完全匹配。但它需要对候选 1 的第一个参数进行用户定义的转换。因此对于第一个参数,第二个候选者获胜。

您还看到第二个位置的结果取决于。让我们做一些假设,看看我们得到了什么:

  1. ptrdiff_tint :第一个候选者获胜,因为它具有完全匹配,而第二个候选者需要整数转换。
  2. ptrdiff_tlong : 两个候选人都没有获胜,因为两者都需要积分转换。

现在,13.3.3/1

Let ICSi(F) denote the implicit conversion sequence that converts the i-th argument in the list to the type of the i-th parameter of viable function F.

A viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then ... for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that ...

对于我们的第一个假设,我们没有获得总冠军,因为候选人 2 赢得了第一个参数,而候选人 1 赢得了第二个参数。我称之为纵横交错。对于我们的第二个假设,候选 2 总体上获胜,因为这两个参数的转化率都较差,但第一个参数的转化率更好

对于第一个假设,第二个参数中的整数转换(int 到 unsigned)与用户定义的第一个参数中另一个候选者的转换相比,这并不重要。在纵横交错中,规则是粗糙的。


最后一点可能会让你感到困惑,因为大家都在大惊小怪,所以让我们举个例子

void f(int, int) { }
void f(long, char) { }

int main() { f(0, 'a'); }

这给了你同样令人困惑的 GCC 警告(我记得,当我几年前第一次收到它时,它实际上把我搞糊涂了),因为 0转换为 long'a' 差至int - 但是你会得到一个模棱两可的地方,因为你是在一个纵横交错的情况下。

关于c++ - 为什么这里会出现这种歧义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3519282/

相关文章:

c++ - 在某个随机命名空间中专门化和定义模板静态成员是否可以?

C++ 重载 operator->() 没有被调用?

c++ - 如何正确重载 '=' 运算符以使用重载 '[ ]' 运算符的数组?

c++ - 模板函数奇怪的链接器错误

c++ - LNK2019带模板

c++ - `cout << x` 和 `cout.operator<<(x)` 和 `operator(std::cout, x)` 之间的区别?

c++ - 为什么 (&array)[i] 不取第 i 个元素的地址?

c++ - 给定以弧度为单位的距离和角度,获取绕点旋转的物体的 X、Y 位置的函数?

c++ - 如何在 makefile 中只编译一个 .h 文件?

c++ - 截断留在 C++ 或通用示例中的整数