我尝试找到一种合理的方法来支持基于各种输入数据类型的类的自定义 ID 数据类型。这是什么意思?
假设我们有几个可能的 TD 类型的数据记录 D,从中我们可以导出 TI 类型的 ID。这些数据记录存在于各种容器中。一些例子:
std::vector<int>
std::set<double>
const float* p
和 size_t s
从所有这些容器中,我们可以派生出其元素的 ID。此外,还有一个类
Dummy
需要在内部存储这些ID。我想通过一切手段防止不必要的复制,这就是为什么我不希望 Dummy 的用户首先自己创建 ID 容器,然后将其复制到 Dummy 构造函数。
我的第一个想法是在调用方创建 ID 容器,然后将其移动到虚拟构造函数中。我不能确切地说出为什么,但这对我来说感觉不对(真的,这只是一种直觉)。
最后,我决定寻求一种解决方案,将迭代器传递到调用者的容器,并通过一个小回调来计算每个元素的 ID(请参阅下面的代码)。
这个解决方案有效,但并不是很好,因为模板参数推导在这里不起作用。这意味着,我总是必须写下目标 ID 类型两次 - 在虚拟构造函数中以及在回调中的某个时刻。
总体而言:还有比这更好的解决方案吗?我可以改进我的想法来摆脱“重复的数据类型问题”吗?
#include <string>
#include <vector>
template<typename IdType>
struct Dummy {
template<typename InputIt, typename Converter>
Dummy(InputIt first, InputIt last, Converter convert) {
for (auto it = first; it != last; ++it) {
_ids.push_back(convert(*it));
}
}
std::vector<IdType> _ids;
};
int main() {
std::vector<int> c1{1, 2, 3, 4, 5};
auto d1 = Dummy<std::string>(c1.begin(), c1.end(), [](const auto& c) { return std::to_string(c); });
std::pair<double, double> c2[2] = {{1.0, 2.0}, {3.0, 4.0}};
auto d2 = Dummy<uint32_t>(c2, c2 + 2, [](const auto& c) { return static_cast<uint32_t>(c.first * c.second); });
}
对于CTAD的问题,你可以直接写你的自定义推演指南:
template <class InputIt, class Converter>
Dummy(InputIt first, InputIt last, Converter convert)
-> Dummy<typename std::result_of<Converter(typename std::iterator_traits<InputIt>::value_type)>::type>;
那么,你可以简单地做:
auto d3 = Dummy(c1.begin(), c1.end(), [](const auto& c) { return std::to_string(c); });
auto d4 = Dummy(c2, c2 + 2, [](const auto& c) { return static_cast<uint32_t>(c.first * c.second); });