如何用惯用方式精简临时类实例代码以实现DRY原则?
问题描述
编写代码时常遇到这类场景:需要定义多个同一类型的实例,它们共享通用前缀,且定义差异很小,但难以写出既紧凑又易用的代码。
比如初始代码存在重复的前缀和构造调用:
auto blue_foo = std::make_unique<float[]>(n); auto blue_bar = std::make_unique<float[]>(m); auto blue_baz = std::make_unique<float[]>(k);
尝试用结构体分组来优化调用方式(比如blue.foo代替blue_foo),但结构体定义又过于冗余:
struct { std::unique_ptr<float[]> foo, bar, baz; } blue = { std::make_unique<float[]>(n), std::make_unique<float[]>(m), std::make_unique<float[]>(k), };
想简化结构体成员的类型声明(比如auto foo, bar, baz;)但语法不允许;用lambda封装构造逻辑也仅能减少少量重复,效果有限:
auto make_data = [](std::size_t size) { return std::make_unique<float[]>(size); }; struct { auto foo, bar, baz; } blue = { make_data(n), make_data(m), make_data(k) };
需求:针对这类仅单次使用的代码片段,找到紧凑且可读的惯用优化方法。
惯用优化方法
1. 结构化绑定 + std::tuple(C++17+)
无需定义结构体,直接用tuple打包实例,通过结构化绑定获取命名变量,既消除前缀重复,又保持代码紧凑:
auto [blue_foo, blue_bar, blue_baz] = std::make_tuple( std::make_unique<float[]>(n), std::make_unique<float[]>(m), std::make_unique<float[]>(k) );
如果需要分组访问(类似blue.foo),可以结合匿名结构体和即时lambda初始化:
auto blue = []{ struct { std::unique_ptr<float[]> foo, bar, baz; } data{ std::make_unique<float[]>(n), std::make_unique<float[]>(m), std::make_unique<float[]>(k) }; return data; }();
调用时依然可以用blue.foo,且无需额外的结构体声明。
2. 简化构造逻辑的模板函数
用极简模板函数封装重复的make_unique调用,减少构造代码的重复:
template<typename T> constexpr auto make_array_ptr(std::size_t size) { return std::make_unique<T[]>(size); } // 分组使用版本 auto blue = []{ struct { decltype(make_array_ptr<float>(0)) foo, bar, baz; } data{ make_array_ptr<float>(n), make_array_ptr<float>(m), make_array_ptr<float>(k) }; return data; }(); // 非分组简化版本 auto [foo, bar, baz] = std::make_tuple( make_array_ptr<float>(n), make_array_ptr<float>(m), make_array_ptr<float>(k) );
3. C++20指定初始化器优化结构体定义
利用C++20的指定初始化器,让结构体初始化的可读性大幅提升,避免顺序错误风险,结构也更清晰:
struct { std::unique_ptr<float[]> foo; std::unique_ptr<float[]> bar; std::unique_ptr<float[]> baz; } blue = { .foo = std::make_unique<float[]>(n), .bar = std::make_unique<float[]>(m), .baz = std::make_unique<float[]>(k) };
4. 宏(极端场景下使用)
如果变量数量极多,可以用宏消除前缀和构造重复,但注意宏的可读性和调试性较差,非必要不使用:
#define MAKE_BLUE_ARRAY(name, size) \ auto blue_##name = std::make_unique<float[]>(size); MAKE_BLUE_ARRAY(foo, n); MAKE_BLUE_ARRAY(bar, m); MAKE_BLUE_ARRAY(baz, k);
内容的提问来源于stack exchange,提问作者einpoklum
相关产品推荐
相关产品推荐

