【问题标题】:C++ type-erasing generic functor objectsC++ 类型擦除泛型仿函数对象
【发布时间】:2021-12-28 17:13:25
【问题描述】:

我有一堆实现通用调用运算符的类:

template<typename T = char>
struct match {

    template<initer_of_type<T> IterT>
    constexpr auto operator()(IterT iter) const -> std::optional<decltype(iter)> {
        // ... function body
    }
    // ... some members
}
// ... more similar structs

在类模板中,运算符本身也是一个模板。
注意:我在这里使用的概念是我接受任何返回特定值类型的输入迭代器:

template<typename IterT, typename T>
concept initer_of_type =
    std::input_iterator<IterT>
    && std::is_same_v<typename IterT::value_type, T>;

这样我就可以在任何可迭代的Ts 容器上使用该算法...

我希望能够保存这些对象的数组,所有这些对象都具有相同的模板参数T,但可能是不同的类。似乎我既不能使用普通继承也不能使用类型擦除(至少我知道的方式),因为该函数是一个模板。有没有好的方法来做到这一点?还是我在寻找错误的解决方案?

【问题讨论】:

  • 数组中可能的类型是否有界?
  • std::variant 也许?
  • @Klaus 我觉得应该有更好的方法来做到这一点。使用变体,我必须在任何给定时刻检查包含哪种类型,然后将std::get 排除在变体之外,这对于用户 POV 来说既不方便,又比简单地使用继承产生更大的运行时开销(如果可能的话)。
  • "这对于用户 POV 来说非常不方便,并且比简单地使用继承(如果可能的话)产生更大的运行时开销。"没有运行时开销。
  • 这个问题有一些相似的感觉:stackoverflow.com/questions/70002943/…。我在那里写了一个初步的any_const_input_iterator_of&lt;T&gt;,它可能被用作这些类的常规类型擦除接口中的函数调用运算符的参数。但是,如果您的仿函数类集是预先知道的,那么我肯定会采用variant&lt;match&lt;T&gt;, other_match&lt;T&gt;, third_match&lt;T&gt;&gt; 的方法来处理您所有的match 类类。您还可以将变体隐藏在内部visits 的便捷界面后面。

标签: c++ templates c++20 type-erasure


【解决方案1】:

@chris 评论很棒,如果我的理解是正确的,基本上它会在您的 IterT 上添加一个额外的抽象层,从而使匹配函数能够被擦除(然后存储在某个容器中)

如你所说:

我希望能够保存这些对象的数组,所有这些对象都具有相同的模板参数 T,但可能是不同的类。

所以看来我们必须添加一个新的抽象层来处理这个约束,chris 的观点是从 IterT 开始。我想提供一个从ThreadExecutor窃取的新视角。

一般ThreadExecutor几乎都有这样的接口:

std::future<R> execute(Func&& f, Args&&... args);

和你的情况一样,args 和 return type 都是模板参数,ThreadExecutor 也需要将这些用户传递任务存储在一个容器中。基本上,ThreadExecutor 通过将用户传递任务包装在 packaged_task 中以擦除 arg 类型来处理此问题,然后将 packaged_task 包装在函数包装器或其他东西中以擦除返回类型。

这是一个很幼稚的代码sn-p,直接使用了取值等,但我觉得可以表达基本思想。

struct Container{
    template<typename IterT>
    void add(match<IterT> func, IterT iter){
        store_.push_back(std::function([=](){
            std::packaged_task([=](){
                return func(iter);
            })();
        }));
    }

    std::vector<std::function<void()>> store_;
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多