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

如何在requires表达式中复用函数调用的返回类型?

C++ Concept中拆分f(g(t))调用的可行方案

问题场景

要实现一个Concept,用于校验类型T是否满足:T的实例t能调用g(t),且该调用的返回值可作为f的参数传入。最初的实现如下:

template<typename T>
concept C = requires(T t) {
    f(g(t));
};

配套验证代码:

auto g(int)  -> float;   
auto g(char) -> double; 

void f(float);
void f(double) = delete;

static_assert(C<int>);       // 合法:g(int)返回float,匹配可用的f(float)
static_assert(not C<char>);  // 不合法:g(char)返回double,但f(double)已被删除

这段代码能正常工作,但出于两个原因希望拆分f(g(t))的写法:

  • g可能带有不依赖T的固定参数,直接写完整调用会让代码冗余;
  • 需要在Concept中多次复用g(t)的返回值或类型,避免重复编写调用逻辑。

但以下两种尝试均无法在Concept中生效:

// 尝试1:直接声明变量复用结果
auto res = g(t);
f(res);
// 尝试2:推导返回类型后构造临时对象
using ret_t = decltype(g(t));
f(ret_t{});

尝试2的问题在于,即便g(t)返回类型是ret_t,ret_t{}的构造可能不合法(比如返回类型不可默认构造),且无法准确模拟g(t)返回值的值类别(左值/右值),导致校验结果失真。

可行解决方案

方案1:使用requires表达式的语句块(C++20+)

C++20的requires表达式支持在参数列表后用大括号包裹语句序列,编译器会检查这些语句的合法性。你可以在语句块内声明变量,一次性获取g(t)的结果并多次复用:

template<typename T>
concept C = requires(T t) {
    {
        auto res = g(t); // 仅调用一次g(t),将结果存入res
        f(res);          // 使用res调用f
        other_func(res); // 可多次复用res
    };
};

如果g带有固定额外参数,只需写一次完整调用:

template<typename T>
concept C = requires(T t) {
    {
        auto res = g(t, fixed_arg1, fixed_arg2); // 仅写一次带额外参数的g调用
        f(res);
        another_func(res);
    };
};

这种方式完全模拟实际调用流程,包括值类别传递(比如g(t)返回左值引用时,res会保持引用类型,准确匹配f的参数要求)。

方案2:推导返回类型后用std::declval模拟值(仅适用于类型校验)

如果只需复用g(t)的返回类型,不需要依赖实际返回值的属性,可以用decltype(auto)推导类型,再通过std::declval生成该类型的模拟值:

#include <utility>

template<typename T>
concept C = requires(T t) {
    using ret_t = decltype(g(t));
    f(std::declval<ret_t>());
    // 还可基于ret_t添加额外类型约束
    requires std::convertible_to<ret_t, float>;
};

注意:该方案仅适合纯类型校验场景。如果f对参数的值类别有要求,或者g(t)的合法性依赖t的具体值,这种方法可能产生误判——因为std::declval默认生成右值,无法完全模拟g(t)返回值的实际属性。

验证效果

用方案1修改后的Concept,依然能通过原有的校验逻辑:

auto g(int)  -> float;   
auto g(char) -> double; 

void f(float);
void f(double) = delete;

template<typename T>
concept C = requires(T t) {
    {
        auto res = g(t);
        f(res);
    };
};

static_assert(C<int>);       // 正常通过
static_assert(not C<char>);  // 正常不通过

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 18:22:09