可选成员的decltype

时间:2019-02-06 09:26:23

标签: c++ optional decltype

我正在尝试从std :: optional <>中的struct成员获取类型,该成员是成员函数的返回类型。

这是一个简化的示例:

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 :(得分:6)

如果将实际参数传递给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中使用它。

答案 1 :(得分:0)

马克显示了您问题的直接答案。

但是,我提出了一个易于阅读的解决方案,它借用了标准库对类型别名的高度依赖。他们基本上是免费的,如果在类定义中有点吵:

#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;
}

这具有自我记录的优点,并且不需要仅C ++ Standardese母语者才能理解的70个字符的语句。 :)

它在类定义本身中也具有价值,因为现在您可以在一个地方设置这些类型,并且在语义允许的情况下,可以比过去更轻松地更改它们(当您不得不修改每个成员函数时) ,每个数据成员…)。

一个缺点是两个Result成员的完整性并不那么明显。这是否有问题取决于您的实际代码,尤其是Result的实际大小及其常用方式。作为一种折衷,您可以考虑在该级别上删除类型别名,仅保留Dict::ResultType,然后使用decltype(declval<Dict::ResultType>().pos)进行深入研究。只有您可以决定采用这种方法的程度。