I want to access some class data using operator[]
, but depending on the type of index, one or more data is returned in square brackets. As a simplified example:
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 }; };
It is not possible to write a short
literal, so the only way to choose short
overload is casting:
S s; std::cout << s[9] << '\n'; // prints [i]9 std::cout << s[(short)9] << '\n'; // prints [s]999
But I do not like it, and I was wondering if there are other options.
What have i tried?
Marked Parameter
At first I tried using the "tags":
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 }; };
This works, but still a little more verbose:
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
Template.
As a crazy workaround, I wanted to try the operator pattern:
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]; }
The version of the template behaves like source code, but there is no easy way to specify a type parameter along with 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';
Question.
All the described problems also happen with operator()
, I want to know if there are any other alternatives that I don't know about?