优先考虑一个操作员[]而不是另一个操作员

Giving preference to one operator[] over another

本文关键字:操作员 另一个 一个      更新时间:2023-10-16

考虑以下类:

class Test
{
public:
    Test( char );
    Test( int );
    operator const char*();
    int operator[]( unsigned int );
};

当我使用它时:

Test t;
Test& t2 = t[0];

我发现编译器错误,它无法确定要使用哪个操作员[]。MSVC和GCC均两者。不同的错误。但是同样的问题。

我知道发生了什么。它可以从int或char构建测试,并且可以使用 Test::operator[],也可以施放用于const char*并使用已构建的char*[]

我希望它更喜欢Test::operator[]

有没有办法指定这样的偏好?

更新:首先,我会同意下面的响应,没有任何语言功能可以让您指定转换的优先级。但是,就像下面发现的Juanchopanza一样 - 您可以通过进行一个转换不需要铸件而间接创建如此偏好,而是使另一个需要铸造。例如。unsigned int作为operator[]的参数无法正常工作,但是使用int会。

无论如何,默认索引参数是未签名的 - 对于GCC和MSVC,因此将索引参数无符号会导致编译器更喜欢正确的操作员。

@konrad:关于内置类型的隐式转换。一般同意。但是在这种情况下我需要它。

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

您始终可以制作构造函数explicit - 或者,正如John所指出的那样,省略了转换操作员。我通常建议您做所有这些事情,但是由于您的代码是一个玩具示例,因此很难说您的情况适合您。

也就是说,以下内容应起作用:

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

(请注意添加的const - 否则您将临时绑定到不起作用的非const引用。)

我之前已经实现了像您这样的容器类 - 完全有可能避免歧义问题,同时保持干净,直观的语法。

首先,您需要考虑constness。通常,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和non-const []运算符,则需要两个版本。此捕获的所有成员功能可能看起来像这样(请记住,其定义必须留在您的班级声明中,并且不能移动到实现文件):

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

如果您添加了[]运算符的非const版本,则您也需要:

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

享受!

相关文章: