循环语句的 std::is_same
我有两个结构,其方法在它们拥有的对象集合的开始和结束时返回迭代器。方法有不同的名称(这似乎是一个糟糕的应用程序架构,但这只是一个简化的模型):
struct A {
std::vector<int>::iterator a_begin() { return v.begin(); }
std::vector<int>::iterator a_end() { return v.end(); }
std::vector<int> v = { 1, 2 };
};
struct B {
std::vector<float>::iterator b_begin() { return v.begin(); }
std::vector<float>::iterator b_end() { return v.end(); }
std::vector<float> v = { 1.0f, 2.0f };
};
我想编写一个模板函数,它将迭代给定的对象(类型 A 或类型 B)并对其元素做一些工作。我的做法是:
template<class T>
void foo(T t) {
if constexpr (std::is_same_v<T, A>) {
for (auto it = t.a_begin(); it != t.a_end(); it++) {
// a lot of stuff
}
} else if constexpr (std::is_same_v<T, B>) {
for (auto it = t.b_begin(); it != t.b_end(); it++) {
// the same stuff
}
}
}
因为for循环体是相同的,所以对我来说看起来有点难看。有什么办法可以改善这种情况吗?
回答
我从表面上接受你关于命名和复杂性的主张,如此抽象和桥梁。
namespace detail {
inline auto foo_begin(A& a) { return a.a_begin(); }
inline auto foo_end (A& a) { return a.a_end(); }
inline auto foo_begin(B& b) { return b.b_begin(); }
inline auto foo_end (B& b) { return b.b_end(); }
}
template<class T>
void foo(T t) {
for (auto it = detail::foo_begin(t); it != detail::foo_end(t); ++it) {
// the same stuff
}
}
您想要改变的操作是范围选择。因此,为您关心的类型设置一个小的重载应该可以很好地完成。
如果您经常这样做,可能值得考虑使用范围适配器。您可以手动编写它,或者使用 C++20 编写它,std::ranges::subrange您甚至可以利用这个重载集本身。
template<class T>
void foo(T t) {
for (auto &item : std::ranges::subrange(detail::foo_begin(t), detail::foo_end(t))) {
// the same stuff
}
}