gpt4 book ai didi

c++ - 不完整类型的调用运算符的 decltype 的特殊行为

转载 作者:可可西里 更新时间:2023-11-01 18:37:30 24 4
gpt4 key购买 nike

我一直在努力解决编译问题,并且能够将问题缩小到一个小代码段。

为了做好准备,我正在尝试执行 CRTP,其中基方法调用派生类中的另一个方法。复杂的是,我想使用尾随返回类型来直接获取转发到派生类方法的类型。这总是无法编译除非我转发给派生类中的调用运算符。

编译:

#include <utility>

struct Incomplete;

template <typename Blah>
struct Base
{
template <typename... Args>
auto entry(Args&&... args)
-> decltype(std::declval<Blah&>()(std::declval<Args&&>()...));
};

void example()
{
Base<Incomplete> derived;
}

虽然这不是:(注意唯一区别的注释)

#include <utility>

struct Incomplete;

template <typename Blah>
struct Base
{
template <typename... Args>
auto entry(Args&&... args)
-> decltype(std::declval<Blah&>().operator()(std::declval<Args&&>()...));
// I only added this ^^^^^^^^^^^
};

void example()
{
Base<Incomplete> derived;
}

我得到的错误:

<source>: In instantiation of 'struct Base<Incomplete>':
15 : <source>:15:22: required from here
10 : <source>:10:58: error: invalid use of incomplete type 'struct Incomplete'
-> decltype(std::declval<Blah&>().operator()(std::declval<Args&&>()...));
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^

在 Derived 类的 decltype 解析过程中似乎有一些特殊的行为发生。标准中有什么可以解释这一点的吗?

编辑:做了更大的简化

PS:godbolt 上的编译示例:https://godbolt.org/g/St2gYC

最佳答案

实例化类模板会实例化其成员函数模板 ([temp.inst]/2) 的声明。 IE。我们正在看声明

template <typename... Args>
auto entry(Args&&... args)
-> decltype(std::declval<Incomplete&>().operator()(std::declval<Args&&>()...));

现在考虑 [temp.res]/10 :

If a name does not depend on a template-parameter (as defined in 14.6.2), a declaration (or set of declarations) for that name shall be in scope at the point where the name appears in the template definition;

事实上,名称 operator() 并不依赖于模板参数。它既不依赖类型也不依赖值,也不是依赖名称。显然,范围内没有声明,因此声明格式错误,不需要诊断。

相比之下,您的第一个片段不需要在 Incomplete 中查找名称。 x(...) 的转换,其中 x 是类类型,到 x.operator()(...) 发生仅在 operator() 在 x 中查找之后— [over.call] :

Thus, a call x(arg1,...) is interpreted as x.operator()(arg1, ...) for a class object x of type T if T​::​operator()(T1, T2, T3) exists and if the operator is selected as the best match function by the overload resolution mechanism ([over.match.best]).

这与使您的第二个代码格式错误的段落不同:[temp.res]/10 表示某些声明 必须在范围内,并且名称是绑定(bind)的那些声明。上述转换要求参数类型(以及数量...)是已知的,以便我们可以唯一确定要调用的 operator();也就是说,我们不只是插入 .operator(),而是始终同时识别调用了哪个运算符函数。我们可以在 [temp.dep] 中找到对这种解释的进一步证实:

If an operand of an operator is a type-dependent expression, the operator also denotes a dependent name. Such names are unbound and are looked up at the point of the template instantiation [...]

operator() 的参数操作数显然是依赖于类型的。

关于c++ - 不完整类型的调用运算符的 decltype 的特殊行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45518910/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com