c++ 有没有办法从可解除引用的类型中获取解除引用的值的类型?

lfapxunr  于 2023-02-01  发布在  其他
关注(0)|答案(2)|浏览(136)

我正在研究C++的概念,遇到了一个有趣的问题。我有以下两个自定义的概念:

template<typename T>
concept is_dereferencable = requires (T t) { *t; };

template<typename T>
concept is_printable = requires (T t) { std::cout << t; };

顾名思义,第一个函数用于确定给定的类型是否可以解引用,而另一个函数用于检查类型是否支持输出操作符。我还有一个函数模板,名为println,如下所示:

template<typename T>
void println(const T& t)
{
    if constexpr (is_dereferencable<T>) {
        if constexpr (is_printable<decltype(*t)>) {
            std::cout << *t << '\n';
        }
    } else if constexpr (is_printable<T>) {
        std::cout << t << '\n';
    }
}

当且仅当类型T是可解引用的,并且解引用的值的类型是可打印的时,这个函数才会打印解引用的值*t,所以,举个例子,我可以使用这个函数模板,其中包含一个std::optional:

int main
{
    std::optional<std::string> stringOpt {"My Optional String"};
    ::println(stringOpt);

    return 0;
}

这将按预期打印My Optional String。虽然这很好,但如果dereferenceable的解引用值的类型不可打印,则函数将不打印任何内容。因此,对于用户定义类型Person,以下代码将不打印任何内容:

struct Person
{
    std::string m_name;
    explicit Person(const std::string& name) : m_name {name} {}
};

int main
{
    std::optional<Person> personOpt {"John Doe"}
    ::println(personOpt);
    return 0;
}

所以我想把上面的编译时if s移到一个requires子句中,以便在这种情况下得到编译时错误。有没有办法做到这一点?有没有办法得到一个给定模板类型T的解引用类型?为了让它更清楚一点,我想有这样的东西:

template<typename T>
requires is_dereferencable<T> && is_printable<decltype(*T)>
void printDereferencable(const T& t)
{
    std::cout << *t << '\n';
}

**P.S.:**我知道我可以删除嵌套的if,并且在不支持它的地方调用输出操作符时失败。但是,我想特别地将这个编译时错误移到概念中,以获得更清晰的错误消息。

kqlmhetl

kqlmhetl1#

另一个选择是将约束放在参数之后,因此它可以访问它们。

template<typename T>
void printDereferencable(const T& t)
requires is_dereferencable<const T&> && is_printable<decltype(*t)>
{
    std::cout << *t << '\n';
}

注:应在const T&上测试,而不是在T上测试

8xiog9wr

8xiog9wr2#

您可以使用std::declval

template<typename T>
requires is_dereferencable<const T&> && is_printable<decltype(*std::declval<const T&>())>
void printDereferencable(const T& t)
{
    std::cout << *t << '\n';
}

或者你可以写一个is_dereference_printable的概念

template<typename T>
concept is_dereference_printable = requires (T t) { std::cout << *t; };

相关问题