这种情况如何消除几百个 if/else
运行时从外部读取一个 16 进制数字,然后调用对应的函数,比如读取到1F3,那么就调用函数foo_1f3,函数参数也是有编号的,规律是这样:
void foo_1f0(myclass_1f0& val);
void foo_1f1(myclass_1f1& val);
void foo_1f2(myclass_1f2& val);
之前 C#是用的反射,很容易实现。到 C++这不知道怎么搞比较优雅,目前有上百个 if/else 去判断然后调用。
C++这边可以用到 C++20 ,不知道有什么酷的解决方法?
std::map
模板。
你是否在找:工厂模式/策略模式?
感觉你描述的还比较清晰,把你发的这段内容交给 AI,一会就能出来代码~
std::vector<std::function<void(int)>> foos;
参数不同,而且注册也得写几百行,感觉和 if/else 差不多。
注册函数?感觉和 if/else 差不多,也要写上百行。
展开讲讲。。
模板是编译时计算,他这个要求运行时读取,应该做不到吧?
对于分发用的标志 1fx 比较集中的情况,可以直接用 std::vector<std::function<>> 然后用数组下标做 key ;对于 key 比较稀疏的情况,可以用 std::map<int, std::function<>> 或者 std::unordered_map
注册要写几百行这种估计跑不掉的,目前 c++ 还没有正式支持反射;不过可以用部分编译器支持的 [[constructor]] 语法,在启动阶段实现自动注册。例如有某 Dispatcher::register(int, std::function<>) 方法,部分编译器可以实现:
[[gnu::constructor]] reg_handler() { Dispatcher::register(0x1f3, foo_1f3); }对于无反射的静态编译型语言,这种情况 if 和 switch 是最清晰的,因为阅读代码的人只要看三个 if 就知道这坨是干什么的,也非常容易定位和修改,用其他自以为“优雅”的解决方案很大概率只是满足了自己苦了他人。
不想写 ifelse 就 LLM 生成得了
写了一个超省略的 demo ,供参考 godbolt.org/z/ox7K6sM1e
直接 switch ,case 用宏包一下,再用工具生成。
强行搞可以把函数导出,运行时查符号。
怎么感觉你是在搞啥协议解析,前面是 msgID 对应不同的解析函数,去处理后面的 data 部分
wow 这个问题完全 under-specified 。第一个问题:你知道要调用什么函数了,可你怎么制造不同类型的参数传入之?
但楼主不应该尝试回答我的第一个问题,而是应该直接说自己实际上要解决的问题,而不是来问自己觉得可行的一半解决方法的另一半。
额,感觉还得用脚本批量生成函数注册的逻辑。。
void foo_1f0(int& value) { std::cout << "test!!" << std::endl; }
// 这块代码得脚本生成
std::unordered_map<std::string, std::function<void(int&)>> GFunctions = {
{ "foo_1f0", foo_1f0 }
};
int main()
{
int inParam = 0x1f0;
std::stringstream ss;
ss << std::hex<<inParam;
std::string funcName = "foo_" + ss.str();
int param = 1;
GFunctions[funcName](param);
}这样写是最好的
这种情况适宜从整体项目 build 的角度考量,有工程上的设计和考量。如果语言本身没有反射机制,一般用脚本或其他自定义工具,在 Pre-build 阶段生成函数的桩,同时对参数和调用场景做必要的安全检查。这样对于函数实现代码,只要做好必要的标注,就和 C#没什么区别了。
想要酷可以参考 std::visit 的做法. 编译期生成一个 Invoke_array, 下面的例子是从运行期的 int 转特定类型到 lambda 中的例子. 稍微改改就能用于你的需求.
using namespace std;
constexpr std::array cached_type_ints = {1};
struct void_ptr {
int type;
void *ptr;
};
template
template <> struct Int2Type<1> {
using type = int;
};
template
template
class Visitor<Func, std::index_sequence<pos...>> {
public:
using return_type =
std::invoke_result_t<Func, Int2Type<cached_type_ints[0]>::type *>;
using fn_type = return_type ()(Func &&, void );
template <int16_t type_int>
static auto func_wrapper(Func &&func, void *ptr) -> return_type {
using real_type = typename Int2Type<type_int>::type;
return func(static_cast<real_type *>(ptr));
}
static auto visit(Func &&func, const void_ptr &item) -> return_type {
constexpr static std::array<fn_type, cached_type_ints.size()> invoke_map = {
func_wrapper<cached_type_ints[pos]>...};
size_t idx = std::ranges::lower_bound(cached_type_ints.begin(),
cached_type_ints.end(), item.type) -
cached_type_ints.begin();
if (idx >= invoke_map.size() or cached_type_ints[idx] != item.type)
[[unlikely]] {
throw std::bad_variant_access();
}
return invoke_mapidx, item.ptr);
}
};
template
using visitor = Visitor<decltype(func),
std::make_index_sequence<cached_type_ints.size()>>;
return visitor::visit(std::forward
}
inline auto usage() {
auto item = void_ptr{.ptr = new int(1), .type = 1};
visit(
[](auto *ptr) {
print(*ptr);
delete ptr;
},
item);
}
查表 map<key,func>
宏定义
这种需求本来难以简化的,Map<key, func>已经是不错的选择了。
再想继续想办法简化我觉得只能增加后期维护负担。
符号得和得和字符串对上,简单点就是 dlsym ,复杂一点用 linker set ,自己加 map 也可以,就是没那么优雅了。
请问 您是找 “宏” 的使用方法么
反射有没有?
只是平级的 if else 没必要专门消除吧,看起来也是很清晰的。
你要 if else 嵌套很多层,去消除更有意义一点。
咋弄 第一次搞 整个网站 找个有公司的朋友代开发票呗。。。。 发票可以税务局代开 人手不够,可以找我,我可以!!! 某宝 花钱 大佬 留个联系方式 我有个法人名义…
没得时间研究了,熟悉搭建的大佬留个联系方式,小偿 Proxifier 搭服务端? 客户端的话直接用 clash 呢 是的 服务器上干 windows 服务器吗,…
前文: hesudu.com/t/1152294 过了一周电信依旧没动静,我主动联系电信师傅咨询,师傅倒是人挺好,说天天都帮我催着的,说目前还有最后一个流程没走完,还要等等,…
合速度