c++ 用于接受将lambda捕获为构造函数参数并将其存储在类中的语法选项

hmae6n7t  于 2023-02-01  发布在  其他
关注(0)|答案(2)|浏览(79)

我试图编写一个向量 Package 器(indexed_vec),它存储ValueType类型的对象,但其他数据结构(其他类型的向量)通过索引引用这些对象(因为迭代器显然不稳定)。
因此,当在indexed_vec中删除ValueType对象时,必须进行一些内务处理,以保持其他数据结构中的索引是最新的。
因此indexed_vec也存储了2个lambda,它们是索引更改的有效“订阅者”(观察者模式)。
下面的代码可以正常工作,但是构造indexed_vec示例的语法似乎有些笨拙。
有更好的选择吗?我调查了演绎指南,但这显然不起作用。
工厂聚会?
(NOTE:将内部向量公开为公共成员的 Package 器不会保持这种状态,这只是为了减少此处的代码)

#include <cstddef>
#include <iostream>
#include <vector>

template <typename ValueType, typename DeleteIndexCBType, typename ChangeIndexCBType>
struct indexed_vec {
    indexed_vec(DeleteIndexCBType& dcb_, ChangeIndexCBType& ccb_) : dcb(dcb_), ccb(ccb_) {}

    DeleteIndexCBType dcb;
    ChangeIndexCBType ccb;

    std::vector<ValueType> v;

    std::size_t erase(std::size_t index_to_erase) {
        // TODO handle empty vector
        v[index_to_erase] = v.back();
        v.pop_back();
        dcb(index_to_erase);
        ccb(v.size(), index_to_erase); // NOTE v.size() is NOW one off the end, but that's accurate
        return 1;
    }
};

template <typename T>
void print(const std::vector<T>& v) {
  for (auto& e: v) std::cout << e << " ";
  std::cout << '\n';
}
  

int main() {
    std::string context = "captured context";

    auto delete_subscriber = [&context](std::size_t idx) {
        std::cout << "deleter: " << context << ": " << idx << "\n";
    };
    auto change_subscriber = [&context](std::size_t old_idx, std::size_t new_idx) {
        std::cout << "updater: " << context << ": " << old_idx << " => " << new_idx << "\n";
    };

    // this seems clumsy?
    indexed_vec<std::size_t, decltype(delete_subscriber), decltype(change_subscriber)> v1(
        delete_subscriber, change_subscriber);

    v1.v.reserve(10);
    for (std::size_t v = 10; v != 20; ++v) v1.v.push_back(v);

    print(v1.v);
    v1.erase(3);
    print(v1.v);
}
fafcakar

fafcakar1#

简化语法的一个简单方法是将冗长的代码 Package 在工厂函数中,如

template <typename ValueType, typename DeleteIndexCBType, typename ChangeIndexCBType>
auto make_index_vector(const DeleteIndexCBType& dcb_, const ChangeIndexCBType& ccb_)
{
    return indexed_vec<ValueType, DeleteIndexCBType, ChangeIndexCBType>(dcb_, ccb_);
}

使用它可以像下面这样声明v1

auto v1 = make_index_vector<std::size_t>(delete_subscriber, change_subscriber);
polhcujo

polhcujo2#

由于不能只提供三个模板参数中的 * 一个 *,因此普通的推导指南无法工作,但可以将ValueType打包到一个标记中。

template <class T> struct ValueTag {};

template <class ValueType, class DeleteIndexCBType, class ChangeIndexCBType>
struct indexed_vec {
    // added constructor for tag:
    indexed_vec(ValueTag<ValueType>, DeleteIndexCBType& dcb_,
                ChangeIndexCBType& ccb_) :
        dcb(dcb_), ccb(ccb_) {}

    //...

演绎指南:

template<class ValueType, class DeleteIndexCBType, class ChangeIndexCBType>
indexed_vec(ValueTag<ValueType>, DeleteIndexCBType, ChangeIndexCBType) ->
    indexed_vec<ValueType, DeleteIndexCBType, ChangeIndexCBType>;

用法:

indexed_vec v1(ValueTag<size_t>{}, delete_subscriber, change_subscriber);

相关问题