【问题标题】:C++ Templates - The Complete Guide: Understanding footnote comment about decltype and return typeC++ 模板 - 完整指南:了解关于 decltype 和返回类型的脚注注释
【发布时间】:2021-09-27 17:22:57
【问题描述】:

C++ 模板 - 完整指南第 2 版在第 435 页提供了以下代码

#include <string>
#include <type_traits>

template<typename T, typename = void>
struct HasBeginT : std::false_type {};

template<typename T>
struct HasBeginT<T, std::void_t<decltype(std::declval<T>().begin())>>
    : std::true_type {};

并且 cmets 使用 decltype(std::declval&lt;T&gt;().begin()) 来测试在 T 上调用 .begin() 是否有效。

我认为这一切都说得通……

让我吃惊的是脚注中的评论:

除了decltype(<i>call-expression</i>) 不需要非引用,非void 返回类型是完整的,这与其他上下文中的调用表达式不同。改用decltype(std::declval&lt;T&gt;().begin(), 0)确实增加了调用的返回类型是完整的要求,因为返回的值不再是decltype操作数的结果。

我真的不明白。

为了尝试使用它,我尝试使用以下代码查看void 成员begin 的行为

struct A {
    void begin() const;
};

struct B {
};

static_assert(HasBeginT<A>::value, "");
static_assert(!HasBeginT<B>::value, "");

但是无论有没有, 0,这两个断言都会通过。

【问题讨论】:

    标签: c++ templates c++17 decltype void-t


    【解决方案1】:

    您的演示使用void begin() const; 来测试以下内容

    ... 而是添加了调用的返回类型为 complete ...

    的要求

    但是 void 返回类型与不完整的返回类型不同。为此,您可以尝试

    struct X;
    
    struct A {
        X begin() const;
    };
    

    在这里,X 确实不完整,现在, 0 很重要。有了它,第一个static_assert 不会通过,但没有, 0 会通过。

    demo

    【讨论】:

    • ...因为逗号可能超载了。
    • 是的,答案真实地说明了我是如何误读/误解了文本的。但是知道我知道我应该如何阅读它,我仍然不明白它是如何工作的。为什么comme会有这种效果?
    • @Enlico 实际上,我不确定它为什么会产生这种效果。 StoryTeller 的评论似乎暗示了这一点,但我不确定我明白为什么。我看看能不能解决您可以编辑问题以询问为什么,但这可能应该是一个不同的问题。
    • @cigien 在这种情况下不用担心,请继续关注,我会再问一个问题
    • @Enlico cppreference says "类型不必是完整的或有可用的析构函数,可以是抽象的。此规则不适用于子表达式:在decltype(f(g())) 中,g() 必须有完整的类型,但f() 不需要。”所以它不仅仅是逗号,而是任何子表达式。我仍然不知道为什么规则存在。
    猜你喜欢
    • 2021-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-03
    • 2017-02-10
    • 1970-01-01
    • 1970-01-01
    • 2021-04-11
    相关资源
    最近更新 更多