优先考虑一个运营商[]而不是另一个运营商

时间:2012-10-30 21:22:56

标签: c++

考虑以下课程:

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:关于对内置类型的隐式转换。一般同意。但在这种情况下我需要它。

3 个答案:

答案 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) );
}

享受!