Decltype необязательного члена - PullRequest
0 голосов
/ 06 февраля 2019

Я пытаюсь получить тип из члена-структуры, который находится в std :: option <>, который является типом возврата функции-члена.

Это упрощенный пример:

struct Result
{
    int tag;
    int pos;
};

class Dict
{
public:
    std::optional<Result> search(const char *word)
    {
        return Result{ 1,2 };
    }
};

Я бы хотел сделать что-то вроде этого:

int main()
{
    Dict abc;
    decltype(abc.search(const char*)->pos) position;

    return 0;
}

Ответы [ 2 ]

0 голосов
/ 06 февраля 2019

Марк показал прямой ответ на ваш вопрос.

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

#include <optional>

struct Result
{
    using TagType = int;
    using PosType = int;

    TagType tag;
    PosType pos;
};

class Dict
{
public:
    using ResultType = Result;

    std::optional<ResultType> search(const char* word)
    {
        return ResultType{ 1, 2 };
    }
};

int main()
{
    Dict abc;
    Dict::ResultType::PosType position;
}

Преимущество этого заключается в самодокументировании и отсутствии необходимости в выражении из 70 символов, которое могут понять только носители языка C ++ Standardese.:)

Он также имеет значение внутри самих определений классов, потому что теперь у вас есть одно место для установки этих типов, и, если позволяет семантика, их можно изменить легче, чем в прошлом (когда вам приходилосьизменить каждую функцию-член, каждый элемент данных…).

Недостатком является то, что сущность двух Result членов не так очевидна.Является ли это проблемой, зависит от вашего реального кода, в частности от фактического размера Result и от того, как он часто используется.В качестве компромисса вы можете рассмотреть возможность удаления псевдонимов типов на этом уровне, сохраняя только Dict::ResultType, а затем копаясь в нем с помощью decltype(declval<Dict::ResultType>().pos).Только вы можете решить, как далеко зайти с этим подходом.

0 голосов
/ 06 февраля 2019

Если вы передадите фактический параметр в search, он будет работать (наряду с общедоступным search):

https://wandbox.org/permlink/0Q3mLW7SmQW4QshE

#include <optional>

struct Result
{
    int tag;
    int pos;
};

class Dict
{
public:
    std::optional<Result> search(const char *word)
    {
        return Result{ 1,2 };
    }
};

int main()
{
    Dict abc;
    decltype(abc.search("")->pos) position;

    return 0;
}

Параметр search не обязательно должен быть действительным (с точки зрения того, что ожидает ваша функция - потому что он на самом деле не будет ее вызывать), это просто должен быть правильный тип.

Если вы хотите иметь дело непосредственно с типамиа не экземпляры, как предлагает ваш комментарий, тогда @ Jarod42 указывает, что вы можете использовать следующую строку для объявления переменной:

decltype(std::declval<Dict>().search(std::declval<const char*>())->pos) position;

https://wandbox.org/permlink/kZlqKUFoIWv1m3M3

Хотя мне, вероятно, не нужно указывать, насколько нечитабелен тип переменной ~ 70 символов.Я думаю, что если бы это был я, я бы либо просто использовал int, либо я создал бы псевдоним типа для pos, например, using ResultPositionType = int;, затем использовал бы это в вашей структуре Result, и снова в main.

...