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

如何消除C++运行时类型调用中的样板代码?

问题描述

我有一些简化后的代码:

inline Type f(const int*) { return Type::Int; }
inline Type f(const double*) { return Type::Double; }
inline void g(int) { }
inline void g(double) { }

类型是运行时管理的枚举:

enum class Type { Int, Double };

我想写一个工具函数,把运行时的Type转换为模板参数,避免重复写大量样板代码。目前的实现如下,do_call_f()和do_call_g()里有很多重复的分支判断:

void do_call_f(Type t)
{
    if (t == Type::Int)
    {
        const auto result = f(static_cast<const int*>(nullptr));
    }
    if (t == Type::Double)
    {
        const auto result = f(static_cast<const double*>(nullptr));
    }
}

void do_call_g(Type t)
{
    if (t == Type::Int)
    {
        g(123);
    }
    if (t == Type::Double)
    {
        g(1.23);
    }
}

int main()
{
    do_call_f(Type::Int);
    do_call_f(Type::Double);

    do_call_g(Type::Int);
    do_call_g(Type::Double);
}

我尝试过各种模板技巧但没成功,期望的工具函数大致像这样的伪代码:

template<typename TFunc, typename TArg>
auto invoke(Type t, TFunc func, TArg&& arg)
{
   if (t == Type::Int)
      return func<char>(std::forward<TArg>(arg));
   if (type == Type::Double)
      return func<double>(std::forward<TArg>(arg));
   // ...
}

需要兼容C14,也可以提供C23的实现作为参考。

解决方案

C++14 实现

核心思路是建立Type枚举到具体类型的映射,通过分发器统一处理分支逻辑,避免重复编写判断代码:

#include <utility>
#include <stdexcept>

enum class Type { Int, Double };

// 类型-枚举映射模板,特化每个类型对应的枚举值
template<typename T> struct TypeMap;
template<> struct TypeMap<int> { static constexpr Type value = Type::Int; };
template<> struct TypeMap<double> { static constexpr Type value = Type::Double; };

// 自定义type_identity,C++14标准库未提供
template<typename T>
struct type_identity { using type = T; };
template<typename T>
using type_identity_t = typename type_identity<T>::type;

// 通用分发函数:根据Type枚举值调用对应类型的处理逻辑
template<typename F>
auto dispatch(Type t, F&& func) {
    switch(t) {
        case Type::Int: return std::forward<F>(func)(type_identity_t<int>{});
        case Type::Double: return std::forward<F>(func)(type_identity_t<double>{});
        default: 
            throw std::invalid_argument("Unknown Type");
    }
}

现在可以用这个分发器简化原来的调用逻辑:

inline Type f(const int*) { return Type::Int; }
inline Type f(const double*) { return Type::Double; }
inline void g(int) { }
inline void g(double) { }

void do_call_f(Type t) {
    dispatch(t, [](auto tag) {
        using T = typename decltype(tag)::type;
        const auto result = f(static_cast<const T*>(nullptr));
        // 这里可以添加result的处理逻辑
    });
}

void do_call_g(Type t) {
    dispatch(t, [](auto tag) {
        using T = typename decltype(tag)::type;
        if (std::is_same<T, int>::value) {
            g(123);
        } else if (std::is_same<T, double>::value) {
            g(1.23);
        }
    });
}

// 如果需要返回值,分发器也支持(所有分支返回类型需一致)
Type call_f(Type t) {
    return dispatch(t, [](auto tag) {
        using T = typename decltype(tag)::type;
        return f(static_cast<const T*>(nullptr));
    });
}

C++23 实现

C++23的模板lambda、std::visit和std::variant能让实现更简洁:

#include <variant>
#include <stdexcept>
#include <type_traits>

enum class Type { Int, Double };

// 将Type枚举转换为对应类型的variant
constexpr auto type_to_variant(Type t) {
    switch(t) {
        case Type::Int: return std::variant<int, double>(int{});
        case Type::Double: return std::variant<int, double>(double{});
        default: throw std::invalid_argument("Unknown Type");
    }
}

// 通用invoke函数
template<typename F>
auto invoke(Type t, F&& func) {
    return std::visit([&func]<typename T>(T) {
        return func.template operator()<T>();
    }, type_to_variant(t));
}

使用时直接借助模板lambda指定类型参数:

inline Type f(const int*) { return Type::Int; }
inline Type f(const double*) { return Type::Double; }
inline void g(int) { }
inline void g(double) { }

void do_call_f(Type t) {
    invoke(t, []<typename T>() {
        const auto result = f(static_cast<const T*>(nullptr));
    });
}

void do_call_g(Type t) {
    invoke(t, []<typename T>() {
        if constexpr(std::same_as<T, int>) {
            g(123);
        } else if constexpr(std::same_as<T, double>) {
            g(1.23);
        }
    });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 21:32:38