问题描述
考虑我有以下最小代码:
#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:在函数'int main(int,char **)'中:
test.cpp:16:error:ISO C ++说是不明确的,即使第一个的最坏转换好于第二个的最坏转换:
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 [] ,int)< built-in>
我的问题是:
- 为什么GNU C ++给出错误,但是Intel C ++编译器不是?
- ] 到以下导致编译没有错误?
$ b
我可以看到两个转换路径:
- ) int 到 size_t 和(2) operator [](size_t)。
- (1) operator ptr_t&(),(2) int 到 size_t 和(3)内置 operator [](size_t)。
解决方案这是很直接的。对于 t [1] ,重载解析有这些候选人:
候选1(内置: 13)(T是某种任意对象类型):
- 参数列表: ptrdiff_t)
候选人2(您的运营商) b
$ b- 参数列表:(TData< float [100] [100]& something,uns unsigned)
参数列表由 13.3.1.2/6 :
- 参数列表:(TData< float [100] [100]> ;, int)
第一个参数完全匹配候选2的第一个参数。但是它需要用户为Candidate 1的第一个参数定义转换。因此对于第一个参数,第二个候选者获胜。
您还可以看到第二个位置的结果取决于。让我们做一些假设,看看我们得到了什么:
- ptrdiff_t $ c> int :第一个候选者获胜,因为它有一个完全匹配,而第二个候选者需要一个完整的转换。
- ptrdiff_t 是 long :两个候选都不会获胜,转换。
现在, 13.3.3 / 1 说
对于我们的第一个假设,我们没有得到一个整体的赢家,因为候选2赢得第一个参数,候选1赢得第二个参数。我称之为交叉。对于我们的第二个假设,候选2胜过整体,因为两个参数都没有更差的转换,但第一个参数有一个更好的转换。
对于第一个假设,第二个参数中的整数转换(int到无符号)比其他参数的用户定义转换候选者在第一个参数。在十字交叉,规则是粗糙的。
最后一点可能仍然让你困惑,因为所有的事情,让我们举一个例子
void f(int,int){}
void f(long,char){}
int main(){f(0,'a'); }
这会给你一个混乱的GCC警告(我记得, ),因为 0 转换为 long 比'a'到 int - 但你却有歧义,因为你处于交叉状态。
Consider I have the following minimal code:
#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++ gives me the error:
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>
My questions are:
- Why GNU C++ gives the error, but Intel C++ compiler is not?
- Why changing operator[] to the following leads to compiling without errors?
As I can see here are two conversion paths:
- (1)int to size_t and (2)operator[](size_t).
- (1)operator ptr_t&(), (2)int to size_t and (3)build-in operator[](size_t).
解决方案It's actually quite straight forward. For t[1], overload resolution has these candidates:
Candidate 1 (builtin: 13.6/13) (T being some arbitrary object type):
- Parameter list: (T*, ptrdiff_t)
Candidate 2 (your operator)
- Parameter list: (TData<float[100][100]>&, something unsigned)
The argument list is given by 13.3.1.2/6:
- Argument list: (TData<float[100][100]>, int)
You see that the first argument matches the first parameter of Candidate 2 exactly. But it needs a user defined conversion for the first parameter of Candidate 1. So for the first parameter, the second candidate wins.
You also see that the outcome of the second position depends. Let's make some assumptions and see what we get:
- ptrdiff_t is int: The first candidate wins, because it has an exact match, while the second candidate requires an integral conversion.
- ptrdiff_t is long: Neither candidate wins, because both require an integral conversion.
Now, 13.3.3/1 says
For our first assumption, we don't get an overall winner, because Candidate 2 wins for the first parameter, and Candidate 1 wins for the second parameter. I call it the criss-cross. For our second assumption, the Candidate 2 wins overall, because neither parameter had a worse conversion, but the first parameter had a better conversion.
For the first assumption, it does not matter that the integral conversion (int to unsigned) in the second parameter is less of an evil than the user defined conversion of the other candidate in the first parameter. In the criss-cross, rules are crude.
That last point might still confuse you, because of all the fuss around, so let's make an example
void f(int, int) { } void f(long, char) { } int main() { f(0, 'a'); }
This gives you the same confusing GCC warning (which, I remember, was actually confusing the hell out of me when I first received it some years ago), because 0 converts to long worse than 'a' to int - yet you get an ambiguity, because you are in a criss-cross situation.
这篇关于为什么这里的模糊?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!