Оператор квадратные скобки и скобка: Как выбирать правильную перегрузку?

Я хотел бы согласиться на некие данные о классе используя оператор квадратные скобки ([]) но в зависимости от типа индекса внутри квадратных скобок возвращать тип информации или другой. Как упрощенный пример:

struct S
{
    int   &operator []( int indice ) { std::cout << "[i]"; return i_bufer[indice]; }
    short &operator [](short indice) { std::cout << "[s]"; return s_bufer[indice]; }

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

Не существует способ писать буквального типа short, так что единственный способ выбирать перегрузку short он с превращением типов:

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

Но это приближение мне не нравится и я осведомлялся о, есть ли другие выборы.

Что я попробовал?

Приклеенные этикетку параметры.

Во-первых я попробовал приклеивать этикетку на параметры:

struct S
{
    enum class tipo_i : std::int32_t {};
    enum class tipo_s : std::int32_t {};

    int   &operator [](tipo_i indice)
    { std::cout << "[i]"; return i_bufer[static_cast<int>(indice)]; }
    short &operator [](tipo_s indice)
    { std::cout << "[s]"; return s_bufer[static_cast<int>(indice)]; }

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

Функционируй, но он немного болтливый:

S s;
std::cout << s[9] << '\n';            // error, no hay sobrecarga disponible
std::cout << s[S::tipo_i{9}] << '\n'; // muestra [i]9
std::cout << s[S::tipo_s{9}] << '\n'; // muestra [s]999

Шаблон.

Как сумасшедшая идея, я захотел попробовать делать шаблон оператора:

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

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

template <>
int   &S::operator [](int indice)   { std::cout << "[i]"; return i_bufer[indice]; }
template <>
short &S::operator [](short indice) { std::cout << "[s]"; return s_bufer[indice]; }

Версия шаблона ведет себя как первоначальная версия, но не существует способ, легкий для того, чтобы параметр - тип быть определенным вместе с оператором:

S s;
std::cout << s[9] << '\n';        // muestra [i]9 igual que antes
std::cout << s[(short)9] << '\n'; // muestra [s]999 igual que antes
std::cout << s<short>[9] << '\n'; // s no es una plantilla
std::cout << s[9]<short> << '\n'; // sin sentido
// Correcto, pero completamente verboso y dificil de leer y escribir
std::cout << s.operator[]<short>(9) << '\n';

Вопрос.

Описанные проблемы происходят также с действующей скобкой, я хотел бы знать, есть ли больше альтернатив, чем я не осознаю.

3
задан 25.01.2017, 12:51
0 ответов

Не существует способ писать буквального типа short, так что единственный способ выбирать перегрузку short - с превращением типов

Действительно нет способа писать буквальный тип short... любой casteo в short он должен будет быть ясным, так как, если не составитель интерпретирует стоимость как int и, как следствие, он реализует первый вызов.

Но это приближение мне не нравится и я осведомлялся о, есть ли другие выборы.

И что является тем, что тебе не нравится точно вышеупомянутого решения?

Конечно решение с templates, для подписи, к которой ты стремишься, не является реальным:

    template <typename T>
    T& operator [](T) { std::cout << "???"; return 0; }
//  ^^                                             ^
// No puedes devolver un literal como referencia!!!

Итак у тебя остаются мало альтернатив:

  • Если ты используешь буквальные, ты будешь должен делать, по крайней мере, ясный cast (он не идет решать это с wrappers ни с templates)
  • Если ты используешь переменные тогда, сам тип переменной будет тем, кто определит в какую функцию он называется.

С другой стороны, если ты ищешь систему, более дружеский pelín, может быть, тебе казался интересным использовать функцию опоры:

struct S
{
    int   &operator []( int indice ) { std::cout << "[i]"; return i_bufer[indice]; }
    short &operator [](short indice) { std::cout << "[s]"; return s_bufer[indice]; }

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

template<class T>
T& Helper(S s, T indice)
{ return s[indice]; }

int main()
{
  S s;
  std::cout << s[9] << '\n';               // muestra [i]9 igual que antes
  std::cout << s[(short)9] << '\n';               // muestra [s]999 igual que antes
  std::cout << Helper<int>(s,9) << '\n';   // muestra [i]9
  std::cout << Helper<short>(s,9) << '\n'; // muestra [s]999
}

Но искренне не только я не вижу ему преимущества в это возможное решение касаюсь но она более обременительная, так как код менее читабельный. Может быть, ты был бы должен описывать более подробно, что тебе не нравится твоего первого решения, чтобы фокусировать наиболее возможные решения.


Я ИЗДАЮ:

Возможное решение (если ты составляешь внизу C ++ 11 или начальника), хотя у него есть Ваш contras, как мы будем видеть, это использование суффиксов, определенных пользователем. Идея тогда состоит в том, чтобы вынуждать пробы немного более чистой формы.

Самый больший недостаток суффиксов состоит в том, что параметр функции должен быть одним эквивалентом типам, перечисленным в следующем списке:

const char*
unsigned long long int
long double
char
wchar_t
char16_t
char32_t
const char*, std::size_t
const wchar_t*, std::size_t
const char16_t*, std::size_t
const char32_t*, std::size_t

Поскольку мы видим, не существует буквальный, ввод которого был int, но если мы имеем unsigned long long int. Понимая, что это не самая рекомендуемая функция кроме того, что он будет использован осторожно, мы можем объявлять следующий суффикс:

constexpr short operator "" _short( unsigned long long int valor)
{
  return static_cast<short>(valor);
}

И сейчас мы это используем:

int main()
{
  S s;
  std::cout << s[9] << '\n';        // muestra [i]9
  std::cout << s[(short)9] << '\n'; // muestra [s]999
  std::cout << s[9_short] << '\n';  // muestra [s]999
}
1
ответ дан 03.12.2019, 17:30
  • 1
    Структура S - só пример. Мой случай использования - класс matriz2D, которые могут быть соглашенными линиями или колоннами. Así так как m.fila(1)[0] возвращает первый элемент второй линии и m.columna(3)[1] возвращает второй элемент четвертой колонны. Querí в notació n двойного крючка: m[columna{3}][1], который является notació n уроженец для массивов. (уже у меня есть helper для возврата действующего крючка). –  25.01.2017, 13:32
  • 2
    @PaperBirdMaster пока ты комментировал он издавал ответ Проверь новую часть посмотрим он служит тебе утилитой. –  25.01.2017, 13:36

struct S вероятно представил что-то, одновременно, у которого i_buffer и s_buffer было какое-то значение. Эта добавочная информация может включаться как часть семантики операторов. Например:

struct Mes {
    Mes(int m) : m(m) {}
    int m;
};

struct Dia {
    Dia(int d) : d(d) {}
    int d;
};

struct S {
    int& operator[](const Mes& mes) 
    {
        std::cout << "[i]";
        return i_bufer[mes.m];
    }
    short& operator[](const Dia& dis) 
    {
        std::cout << "[s]";
        return s_bufer[dis.d];
    }
private:
    int i_bufer[10]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    short s_bufer[10]{ 0, 111, 222, 333, 444, 555, 666, 777, 888, 999 };
};


int main()
{
    S s;
    std::cout << s[Mes(9)] << '\n'; // muestra [i]9
    std::cout << s[Dia(9)] << '\n'; // muestra [s]999
}
0
ответ дан 03.12.2019, 17:30
  • 1
    Это - то, что я сделал, когда я это попробовал " Pará метры маркировок ". –  26.01.2017, 15:47
  • 2
    @PaperBirdMaster В форме использования они могут поверните сходные, но это различные концепции :) –  26.01.2017, 15:53
  • 3
    Tú ты использовал одна struct, я usé enum class практикантка, то же поведение с различным aproximació n. –  26.01.2017, 15:54
  • 4
    Очень грациозный, но нет. –  26.01.2017, 16:05
  • 5
    Я не вижу изящество. Я даже не вижу различия, между одним struct использует для desambiguar вызовы и использовать одну enum class для того же propó расположенный. Оба случая используют тип, дифференцированный для desambiguar вызовы. ¿ Есть что-то, что я esté сходя высоким? –  26.01.2017, 16:12

Теги

Похожие вопросы