c++ - 方括号和圆括号运算符,如何选择重载?

标签 c++ operator-overloading

我想使用 operator[] 访问某些类数据,但根据方括号中的索引类型返回一种数据或其他数据。作为一个简化的例子:

struct S
{
    int   &operator []( int index ) { std::cout << "[i]"; return i_buffer[index]; }
    short &operator [](short index) { std::cout << "[s]"; return s_buffer[index]; }

private:
    int   i_buffer[10]{ 0,  1,   2,   3,   4,   5,   6,   7,   8,   9  };
    short s_buffer[10]{ 0, 111, 222, 333, 444, 555, 666, 777, 888, 999 };
};

无法编写short 字面量,因此选择short 重载的唯一方法是强制转换:

S s;
std::cout << s[9] << '\n';        // prints [i]9
std::cout << s[(short)9] << '\n'; // prints [s]999

但我不喜欢它,我想知道是否有不同的选择。

我尝试了什么?

标记参数。

首先我尝试使用“标签”:

struct S
{
    enum class i_type : std::int32_t {};
    enum class s_type : std::int32_t {};

    int   &operator [](i_type index)
    { std::cout << "[i]"; return i_buffer[static_cast<int>(index)]; }
    short &operator [](s_type index)
    { std::cout << "[s]"; return s_buffer[static_cast<int>(index)]; }

private:
    int   i_buffer[10]{ 0,  1,   2,   3,   4,   5,   6,   7,   8,   9  };
    short s_buffer[10]{ 0, 111, 222, 333, 444, 555, 666, 777, 888, 999 };
};

这行得通,但仍然有点冗长:

S s;
std::cout << s[9] << '\n';            // error, no possible overload to be taken
std::cout << s[S::i_type{9}] << '\n'; // prints [i]9
std::cout << s[S::s_type{9}] << '\n'; // prints [s]999

模板。

作为一个疯狂的解决方法,我想尝试模板化运算符:

struct S
{
    template <typename T>
    T &operator [](T) { std::cout << "???"; return 0; }

private:
    int   i_buffer[10]{ 0,  1,   2,   3,   4,   5,   6,   7,   8,   9  };
    short s_buffer[10]{ 0, 111, 222, 333, 444, 555, 666, 777, 888, 999 };
};

template <>
int   &S::operator [](int index)   { std::cout << "[i]"; return i_buffer[index]; }
template <>
short &S::operator [](short index) { std::cout << "[s]"; return s_buffer[index]; }

模板版本的行为与原始代码相同,但没有简单的方法来指定类型参数以及 operator[]:

S s;
std::cout << s[9] << '\n';        // prints [i]9 like before
std::cout << s[(short)9] << '\n'; // prints [s]999 like before
std::cout << s<short>[9] << '\n'; // s is not template
std::cout << s[9]<short> << '\n'; // nonsense
// Correct but utterly verbose and hard to write and read
std::cout << s.operator[]<short>(9) << '\n';

问题。

所描述的所有问题也发生在 operator() 中,我想知道是否还有更多我不知道的替代方法?

最佳答案

我认为在您的情况下使用命名方法 比使用operator[] 要好得多,因为两个单独的缓冲区是通过阅读源代码访问。

无论如何,如果您想使用operator[] 方法,您可以使用strong typedefsuser defined literals以最小的语法开销实现类型安全:

BOOST_STRONG_TYPEDEF(std::size_t, int_index)
BOOST_STRONG_TYPEDEF(std::size_t, short_index)

struct S
{
    auto& operator[](int_index i) { /* ... */ }
    auto& operator[](short_index i) { /* ... */ }
};

auto operator "" _ii(unsigned long long int x) { return int_index{x}; }
auto operator "" _si(unsigned long long int x) { return short_index{x}; }

然后您可以按如下方式调用您的方法:

S s;

auto& some_int = s[15_ii];
auto& some_short = s[4_si];

wandbox example

关于c++ - 方括号和圆括号运算符,如何选择重载?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41849671/

相关文章:

c++ - Boost 测试是动态链接还是静态链接?

c++ - 启用 RTTI 的动态_cast 段错误

C++:多项式矩阵的输出

c++ - 从控制台读取并创建类实例

C++:重载数学运算符

c++ - 关于此运算符重载的意见

c++ - 必须具有通用接口(interface)但必须根据传递的子类表现不同的函数(不知道它们是什么!)- C++

c++ - 计算任意大数的阶乘,显示所有数字

c# - 可重载运算符 == 和 !=

c++ - 为什么类型转换运算符不适用于继承的类?