You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将表达式扩展到可调用对象返回类型?参数类型扩展失败原因?

问题:通过可调用对象的返回类型实例化MyClass模板

我想要实现的功能是:通过createMyClass函数传入若干可调用对象,根据这些对象的返回类型来实例化MyClass模板,最终得到MyClass<return_type1, return_type2, ..., return_type_n>类型的实例。

我尝试用decltype(std::declval<Ts>()())获取可调用对象Ts的返回类型,并用折叠表达式(decltype(std::declval<Ts>()()), ...)来扩展,但编译时出现了以下语法错误:

syntax error: ',' was unexpected here
syntax error: unexpected token '...' following 'statement'

相关代码如下:

auto lambda = []() { return 'c'; };

template <typename ... Ts>
struct MyClass
{

};

template <typename ... Ts>
void createMyClass(Ts&& ... ts)
{
    /* SUPPOSED TO CREATE MY CLASS WITH THE RETURN VALUES OF THE CALLABLES */
    MyClass< (decltype(std::declval<Ts>()()), ...)> d;

}


int main()
{
    createMyClass(lambda, lambda);

    
    return 0;
}

请问如何正确将表达式扩展为可调用对象的返回类型?为何当前的参数类型扩展方式会报错?


解答

为什么当前写法报错

你用的(decltype(std::declval<Ts>()()), ...)是逗号运算符的折叠表达式,它的作用是依次执行每个decltype表达式,最终只保留最后一个表达式的结果——这和你想要的“把所有返回类型都作为模板参数”完全不符。而且模板参数列表需要的是多个类型组成的列表,这种逗号折叠的写法在语法上不被允许,编译器会把它解析成单个表达式,无法展开成多个类型参数,因此报错。

正确实现方式

不需要用折叠表达式,直接对每个可调用对象的返回类型做参数包展开即可,修正后的代码如下:

#include <utility> // 必须包含std::declval的头文件

auto lambda = []() { return 'c'; };

template <typename ... Ts>
struct MyClass
{

};

template <typename ... Ts>
void createMyClass(Ts&& ... ts)
{
    // 直接展开每个Ts对应的返回类型作为MyClass的模板参数
    MyClass<decltype(std::declval<Ts>()())...> d;
}


int main()
{
    createMyClass(lambda, lambda);
    return 0;
}
  • decltype(std::declval<Ts>()()):std::declval<Ts>()用于生成Ts类型的右值引用(不需要实际构造对象),调用其operator()后,decltype就能获取到该调用的返回类型。
  • ...直接跟在decltype(...)之后:这是C++参数包展开的标准写法,会把每个Ts对应的返回类型依次展开,最终MyClass的模板参数就是所有可调用对象的返回类型列表,比如传入两个返回char的lambda时,会实例化MyClass<char, char>。

内容的提问来源于stack exchange,提问作者Zebrafish

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 00:05:24