考虑以下课程:
class Test
{
public:
Test( char );
Test( int );
operator const char*();
int operator[]( unsigned int );
};
当我使用它时:
Test t;
Test& t2 = t[0];
我遇到编译器错误,无法确定要使用哪个operator []。 MSVC和Gcc都是。不同的错误。但同样的问题。
我知道发生了什么。它可以从int或char构造一个Test,它可以使用Test::operator[]
,也可以转换为const char *并使用构建的char*[]
。
我希望它更喜欢Test::operator[]
。
有没有办法指定这样的偏好?
更新:首先,我同意以下回复,即没有语言功能可让您指定转化优先级。但就像下面发现的juanchopanza一样 - 你可以通过使一个转换不需要强制转换来间接创建这样的偏好,并使另一个转换需要强制转换。例如。 unsigned int
的参数operator[]
不起作用,但使用int
会。
默认索引参数是无符号的 - 无论如何对于gcc和msvc - 因此使索引参数无符号将导致编译器更喜欢正确的运算符。
@Konrad:关于对内置类型的隐式转换。一般同意。但在这种情况下我需要它。
答案 0 :(得分:3)
不,没有。这种含糊不清是为什么不建议自动转换为其他类型(如operator char*
)的原因。
答案 1 :(得分:2)
您可以随时创建构造函数explicit
- 或者,正如john所指出的那样,省略了转换运算符。我通常建议做所有这些事情,但由于你的代码是一个玩具的例子,很难说你的情况适合。
那说,以下应该有效:
Test const& t2 = t.operator[](0);
(注意添加的const
- 否则你会绑定一个临时的非const引用,这也不起作用。)
答案 2 :(得分:1)
我之前已经实现了像你这样的容器类 - 完全可以避免歧义问题,同时保持干净,直观的语法。
首先,您需要考虑const-ness。通常,const char * cast不会修改对象,因此将其设为const成员函数:
operator const char*() const;
另外,你的[]运算符返回一个int而不是int&,所以这也应该是const:
int operator[]( unsigned int ) const;
如果你想能够为索引元素(mytest [5] = 2)赋值,你可以添加另一个这样的运算符函数(这不会取代上面的const版本 - 保持两者):
int& operator[](unsigned int);
接下来,您将希望接受不仅仅是unsigned int的索引。文字整数具有int类型。为了避免与索引类型相关的问题,您需要重载运算符以替代它们。这些重载只是将索引static_cast到您的本机索引类型,并将其传递给本机重载(本机索引类型的重载)。其中一个重载可能如下:
int operator[]( int idx ) const {
return operator[]( static_cast<unsigned int>(idx) );
}
您可以使用单个模板成员函数来涵盖所有可能性,而不是添加一堆重载。模板函数将用于任何尚未具有非模板重载的索引类型。这种非模板重载的偏好是明确的。从本质上讲,这实现了对首选运算符的请求,但是const-ness不是临时的,因此如果你有一个const和一个非const []运算符,则需要两个版本。这个catch-all成员函数可能看起来像这样(请记住它的定义必须保留在类的声明中,不能移动到实现文件中):
template <typename IT>
int operator[]( const IT& idx ) const {
return operator[]( static_cast<unsigned int>(idx) );
}
如果你添加了[]运算符的非常量版本,那么你还需要:
template <typename IT>
int& operator[]( const IT& idx ) {
return operator[]( static_cast<unsigned int>(idx) );
}
享受!