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

C++:基于传入Lambda返回值的模板特化实现问题

解决方案

C++14 实现

利用SFINAE(Substitution Failure Is Not An Error)特性,通过std::enable_if区分返回值为void和非void的情况,实现两个重载函数,让编译器自动匹配:

#include <boost/date_time/posix_time/posix_time.hpp>
#include <type_traits>
#include <utility>

// 处理返回值为void的可调用对象
template <typename F, typename... Args,
          typename = std::enable_if_t<std::is_void<decltype(std::declval<F>()(std::declval<Args>()...))>::value>>
static void measured_run(double& time, F f, Args&&... args)
{
    auto start = boost::posix_time::microsec_clock::local_time();
    f(std::forward<Args>(args)...);
    auto end = boost::posix_time::microsec_clock::local_time();
    time += (end - start).total_milliseconds();
}

// 处理返回值非void的可调用对象
template <typename F, typename... Args,
          typename = std::enable_if_t<!std::is_void<decltype(std::declval<F>()(std::declval<Args>()...))>::value>>
static auto measured_run(double& time, F f, Args&&... args)
    -> decltype(f(std::forward<Args>(args)...))
{
    auto start = boost::posix_time::microsec_clock::local_time();
    auto result = f(std::forward<Args>(args)...);
    auto end = boost::posix_time::microsec_clock::local_time();
    time += (end - start).total_milliseconds();
    return result;
}

调用方式统一为:

double time = 0.0;
measured_run(time, []() { return false; });
measured_run(time, []() { printf("void\n"); });

C++17 实现

C++17引入的if constexpr允许在编译时进行分支判断,无需拆分两个函数,将逻辑合并到一个模板中:

#include <boost/date_time/posix_time/posix_time.hpp>
#include <type_traits>
#include <utility>

template <typename F, typename... Args>
static auto measured_run(double& time, F f, Args&&... args)
{
    auto start = boost::posix_time::microsec_clock::local_time();
    using ReturnType = decltype(f(std::forward<Args>(args)...));

    if constexpr (std::is_void_v<ReturnType>)
    {
        f(std::forward<Args>(args)...);
        auto end = boost::posix_time::microsec_clock::local_time();
        time += (end - start).total_milliseconds();
    }
    else
    {
        ReturnType result = f(std::forward<Args>(args)...);
        auto end = boost::posix_time::microsec_clock::local_time();
        time += (end - start).total_milliseconds();
        return result;
    }
}

if constexpr会在编译时丢弃未选中的分支,避免void result这类非法代码被实例化,完美解决原代码的编译错误。

C++20 实现

C++20可以借助std::invoke_result_t简化返回类型推导,同时用std::invoke增强可调用对象的兼容性(支持成员函数、函数指针等更多类型):

#include <boost/date_time/posix_time/posix_time.hpp>
#include <type_traits>
#include <utility>
#include <functional> // 用于std::invoke和std::invoke_result_t

template <typename F, typename... Args>
auto measured_run(double& time, F f, Args&&... args)
{
    const auto start = boost::posix_time::microsec_clock::local_time();

    if constexpr (std::is_void_v<std::invoke_result_t<F, Args...>>)
    {
        std::invoke(f, std::forward<Args>(args)...);
        const auto end = boost::posix_time::microsec_clock::local_time();
        time += (end - start).total_milliseconds();
    }
    else
    {
        const auto result = std::invoke(f, std::forward<Args>(args)...);
        const auto end = boost::posix_time::microsec_clock::local_time();
        time += (end - start).total_milliseconds();
        return result;
    }
}

原问题分析

你遇到的编译错误源于:当lambda返回void时,measured_run_ret_val会尝试定义auto result为void类型(C++不允许声明void类型的变量),同时在返回void的函数中使用return result也是非法的。通过上述分情况处理的方式,就能避免这些问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 04:55:03