Адресация кортежей в C++14 по типам - разве это не просто неверное предположение?

Страница Википедии C++14 описывает новую языковую функцию адресации кортежей по типам, с помощью которой вы можете написать:

tuple<string, string, int> t("foo", "bar", 7);
int i = get<int>(t);        // i == 7

Ну, как правило, это терпит неудачу, то есть в общем случае кортеж имеет более одного элемента одного типа. Это довольно специфический (хотя и общепризнанный) вид кортежей, которые имеют одно значение для каждого типа; и этот вид получает вид подразумевает семантику get<T>(t) быть своего рода T-представление t, как будто значения в разных типах так или иначе связаны между собой.

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

1 ответ

Я думаю, что основной мотивацией является то, что решение std::tuple по позиции не очень читабелен или не очень устойчив; из обоснования:

Предположим, у нас есть функция get_employee_info, которая возвращает некоторую информацию о сотрудниках в кортеже. Сказав что-то вроде get<2>(get_employee_info(...), на самом деле не ясно, что мы ищем офис сотрудника. Более того, если позже мы будем заинтересованы в возврате другого атрибута сотрудника, нам может потребоваться настроить индексы по всей программе.

Конечно, это может быть сделано только для уникальных типов. Однако можно использовать, например, классы enum, легкие обертки для таких вещей, как std::stringи т.д., чтобы их было легче читать и поддерживать.

Вот быстрый пример:

#include <tuple>
#include <string>
#include <iostream>

struct FirstName : std::string { using std::string::basic_string; };
struct LastName : std::string { using std::string::basic_string; };

struct EmployeeID
{
    EmployeeID(int id) : employeeID_m(id) { }
    operator int() const { return employeeID_m; }
    const EmployeeID &operator=(int id) { employeeID_m = id; return *this; }
    int employeeID_m;
};

using Record = std::tuple<FirstName, LastName, EmployeeID>;

void printRecord(const Record &r)
{
    std::cout << std::get<FirstName>(r) << " "
        << std::get<LastName>(r)
        << "'s employee ID is "
        << std::get<EmployeeID>(r)
        << std::endl;
}

int main() {

    Record record1 = std::make_tuple(FirstName("Slim"), LastName("Jim"), EmployeeID(12233));
    Record record2 = std::make_tuple(FirstName("Big"), LastName("Bill"), EmployeeID(33221));

    printRecord(record1);
    printRecord(record2);

    return 0;
}

С выходом:

Slim Jim's employee ID is 12233
Big Bill's employee ID is 33221
Другие вопросы по тегам