如何绕过在 decltype 表达式中指定变量
How can I get around specifying variables in decltype expressions?
>假设我有以下示例函数:
template <typename Fn> auto call(Fn fn) -> decltype(fn()) {
return fn();
}
此函数的重要之处在于其返回类型取决于其模板参数,这是可以推断的。因此,最终,返回类型取决于函数的调用方式。
现在,我们还有一个测试类:
struct X {
int u;
auto test() -> decltype(call([this]() -> double {this->u = 5; return 7.4;})) {
return call([this]() -> double {this->u = 5; return 7.4;});
}
};
如您所见,X::test
调用call
,返回相同的返回值。在这种情况下,返回类型很简单地给出 double
,但让我们假设我们不知道call
做什么,并且 lambda 具有更复杂的返回类型。
如果我们尝试编译它,编译器会抱怨,因为我们在顶层使用this
(而不是在允许表达式的作用域中(:
error: lambda-expression in unevaluated context
error: invalid use of ‘this’ at top level
但是,我必须使用我传递给call
的lambda的捕获,以便正确获得call
的返回类型。您建议如何在离开lambda的同时解决此问题?
注意:当然,我可以将 lambda 移动到某种帮助程序类型的operator()
,我使用 this
指针的副本实例化它,但我想避免使用那个样板文件。
我认为真正需要关注的错误是"未求值上下文中的lambda表达式"。您不能在未计算的上下文中使用 lambda,因为每个 lambda 表达式都有一个唯一的类型。也就是说,如果允许decltype([]{})
,它将推断出与在其他上下文中[]{}
不同的类型。即 decltype([]{}) fn = []{};
行不通。
除非您只想显式编写返回类型而不是推导它,否则我认为您别无选择,只能创建一个可以在您需要的上下文中使用的真实类型,无论需要什么样板。
尽管如果将test
更改为不是成员函数是可以接受的,那么您可以使用 lambda 可以通过省略它来推断其返回类型的事实,如果主体只是一个 return 语句:
template <typename Fn> auto call(Fn fn) -> decltype(fn()) {
return fn();
}
struct X {
int u;
};
int main() {
auto test = [](X *x) { return call([x]() -> double {x->u = 5; return 7.4; });};
X x;
test(&x);
}
如果函数的尾随返回类型语法具有相同的属性,那就太好了。我不知道为什么没有。
似乎是一个编造的(解释的,人为的(问题,因为
如果您从其他地方获得 lambda,那么它将被命名,绑定
this
没有问题。如果您没有从其他地方获取 lambda,那么您就知道结果类型。
简而言之,正如目前所述问题(当我写这个答案时(,除了你自己的意愿强加的问题之外,没有问题。
但是,如果您坚持这一点,那么,只需将this
作为参数传递,而不是通过lambda定义绑定它。然后,对于 call
的调用,绑定参数。但是,也许不用说,既然这只能解决一个虚构的问题,那么它就是一个真正的鲁布·戈德堡(Rube Goldberg(结构,一个体面的过度开花的不必要的复杂性,除了它自己的复杂性之外,它没有解决任何真正的问题。
如果有的话,最初的真正问题是什么?
你不应该总是复制并粘贴函数体来decltype
.引入后期指定的返回类型的要点是,您将能够以某种方式从参数推断出正确的返回类型。
例如 auto f(T x) -> decltype(g(x)) { return h(), g(x); }
,而不是-> decltype(h(), g(x))
因此,在您的情况下,double test()
就足够了,因为我们知道call
的行为,并且我们知道我们传递给它的 lambda 函数的返回类型。
在更复杂的情况下,我们应该通过使用有关call
和其他东西的知识来减少decltype
中的代码。
- 错误:constexpr 变量'struct2Var'必须由常量表达式初始化
- std::cout 在打印变量与函数表达式时的行为不同
- 如何在 lambda 表达式中传递变量?
- 表达式必须具有常数值,变量不能用作定义数组大小的常数
- C++ 在方程中使用变量;错误:表达式必须具有整数或无作用域枚举类型及其他
- 代码样式:在 switch/if 语句的分支中重用控件表达式或控制变量
- 编译器在传递 const 变量时返回错误:模板参数不是常量表达式
- C++ 使用变量而不是常量表达式初始化数组
- lambda 表达式中引用捕获的 constexpr 变量和非显式捕获的 constexpr 变量之间的区别
- 如何从字符串变量为正则表达式构建原始字符串
- 变量在常量表达式中可用的条件
- QT连接:使用lambda表达式重置通过了int变量(怪异)
- 通过引用传递表达式与通过引用传递变量
- 错误!Constexpr变量必须通过常数表达式constexpr初始化
- 没有变量声明为函数,但错误:二进制表达式的操作数无效
- 常量表达式中引用类型的变量
- 如何将表达式转换为变量
- 从C++调用 Python 或 Lua 来计算表达式,仅在需要时计算未知变量
- ExprTK 未知变量分辨率取决于表达式类型
- 对条件表达式结果的赋值(其中第二个和第三个操作数是相同类型和值类别的变量)是否仍然存在?