我想使用 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 typedefs和 user 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];
关于c++ - 方括号和圆括号运算符,如何选择重载?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41849671/