2

考虑以下类:

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

4

3 回答 3

3

不,没有。而这种歧义就是为什么operator char*不建议自动转换为另一种类型(如 )的原因。

于 2012-10-30T21:24:28.337 回答
2

您总是可以创建构造函数explicit——或者,正如 john 所指出的,省略转换运算符。我通常建议做所有这些事情,但由于您的代码是一个玩具示例,因此很难说出适合您情况的内容。

也就是说,以下应该有效:

Test const& t2 = t.operator[](0);

(注意添加const- 否则您会将临时绑定到非常量引用,这也不起作用。)

于 2012-10-30T21:25:25.417 回答
1

我之前已经实现了像你这样的容器类——完全有可能在保持简洁、直观的语法的同时避免歧义问题。

首先,您需要考虑 const-ness。通常, const char* 强制转换不会修改对象,因此将其设为 const 成员函数:

operator const char*() const;

此外,您的 [] 运算符返回一个 int 而不是 int&,所以这也应该是 const:

int operator[]( unsigned int ) const;

如果您希望能够为索引元素(mytest [5] = 2)分配一个值,您将添加另一个像这样的运算符函数(这不会替换上面的 const 版本——保留两者):

int& operator[](unsigned int);

接下来,您将希望接受不仅仅是 unsigned int 的索引。文字整数具有 int 类型。为避免与索引类型相关的问题,您需要重载运算符以获得替代方案。这些重载只会将索引静态转换为您的本机索引类型并将其传递给本机重载(用于本机索引类型的重载)。这些重载之一可能如下所示:

int operator[]( int idx ) const {
    return operator[]( static_cast<unsigned int>(idx) ); 
}

您可以使用单个模板成员函数来涵盖所有可能性,而不是添加一堆重载。模板函数将用于任何还没有非模板重载的索引类型。这种对非模板重载的偏好是明确的。本质上,这实现了您对首选运算符的请求,但 const-ness 不是可模板化的,因此如果您有一个 const 和一个非常量 [] 运算符,则需要两个版本。这个包罗万象的成员函数可能看起来像这样(请记住,它的定义必须保留在类的声明中,并且不能移动到实现文件中):

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

享受!

于 2012-10-31T01:17:17.657 回答