【问题标题】:unpack variadic template with scoped_ptr使用 scoped_ptr 解压可变参数模板
【发布时间】:2014-04-14 21:00:01
【问题描述】:

我正在使用可变参数模板,我想找到解压参数的好方法

template <typename kernel_type, typename ...kernel_types>
class MetaKernel : public MyKernel<kernel_type, kernel_types...> {
public:
    MetaKernel (
        unsigned int m,
        unsigned int n,
        const kernel_type& kernel_,
        const kernel_types&... kernels_
    ) :
        MyKernel<kernel_type, kernel_types...>(m, n)
    {
        Ks.set_max_size(sizeof...(kernel_types));
        Ks.set_size(sizeof...(kernel_types));
        // for each kernels_, add a MyObsKernel to Ks
        // Ks[sizeof...(kernel_types)].reset((new MyObsKernel<kernel_type, kernel_types...>(kernels_, prototypes_, m, n))...);
    }
private:
    array < scoped_ptr < MyObsKernel<kernel_type, kernel_types...> > > Ks;
}

从文档 (http://en.cppreference.com/w/cpp/language/parameter_pack) 中,我看到了如何像这样解包:

int dummy[sizeof...(Ts)] = { (std::cout << args, 0)... };

但是当我正在处理 scoped_ptr 表时,我需要使用“重置”来初始化它。所以我的解决方案不起作用。如何使用 scoped_ptr 解压缩参数?

感谢您的帮助, 杰罗姆

【问题讨论】:

  • 你上面的课不完整。 Ks 是会员吗?是什么类型的?是std::array吗?如果是这样,它的大小在哪里?你想reset()Ks的每个元素吗?
  • 是的,Ks 是 MetaKernel 类的成员。它是 scoped_ptr 的 dlib 数组,在初始化这样的对象时,我需要重置内容。 (我添加了大小初始化步骤)

标签: c++ templates


【解决方案1】:

您可以使用初始化列表初始化std::array。以下可能会有所帮助:https://ideone.com/PTwatb

MetaKernel (unsigned int m, unsigned int n, const kernel_type& kernel_, const kernel_types&... kernels_) :
    MyKernel<kernel_type, kernel_types...>(m, n),
    Ks({scoped_ptr<MyObsKernel<kernel_type, kernel_types...> >(new MyObsKernel<kernel_type, kernel_types...>(kernels_, kernel_, m, n))...})
{
}

【讨论】:

  • 这看起来确实比我的方法简单得多,但我想我们应该为每个元素调用方法reset(),我不知道这意味着什么。但是如果我们只需要初始化,那么调用一些reset() 是一件愚蠢的事情。当然,假设scoped_ptr 中有这样一个构造函数(这看起来很合理,但我还是不知道)。
  • 感谢您的回复,我使用了这个解决方案,但是由于我使用的是 dlib,并且没有构建器将 initializer_list 用于他们的数组类。我必须使用 initializer_list 添加一个构建器,并且你给我的解决方案是有效的。
【解决方案2】:

正如我在评论中所说,您的问题不完整。我知道Ks 是大小为N = sizeof...(kernel_types)std::array,并且您想在每个元素上调用reset()。如果是这样,这里有一个解决方案:

struct _do { template<typename... A> _do(A&&...) { } };

template <typename kernel_type, typename ...kernel_types>
class MetaKernel : public MyKernel<kernel_type, kernel_types...>
{
    using Base = MyKernel<kernel_type, kernel_types...>;
    using Obs  = MyObsKernel<kernel_type, kernel_types...>;
    static constexpr size_t N = sizeof...(kernel_types);

public:
    MetaKernel (
        unsigned int m,
        unsigned int n,
        const kernel_type& kernel_,
        const kernel_types&... kernels_
    ) : Base(m, n)
    {
        reset(std::make_integer_sequence<size_t, N>(), m, n, kernels_...);
    }

private:
    template<size_t... I>
    void reset (
        std::integer_sequence<size_t, I...>,
        unsigned int m,
        unsigned int n,
        const kernel_types&... kernels_
    )
    {
        _do{Ks[I].reset(new Obs(kernels_, /*prototypes_,*/ m, n))...};
    }

    array <scoped_ptr <Obs>, N> Ks;
};

我正在使用辅助对象 _do 和 C++14 功能 std::integer_sequence, std::make_index_sequence。如果这个不可用,可以查看Rangehere,其中_do也有说明。

除了构造函数之外,您还需要第二个函数来推导出索引包I... 并使用它与参数kernels_... 对齐,以便每个参数在@ 的一个元素上的reset() 调用中恰好使用一次987654338@.

如果你有更多这样的解包操作,最好在整个类中有I...,直接使用。然后,您将只需要第二个 MetaKernelImpl 类,而不是为每个函数添加第二个版本。此类将有一个额外的模板参数,专用于std::integer_sequence&lt;size_t, I...&gt;,用于某些推导包size_t... I。再次查看Callerhere,看看如何做到这一点。

【讨论】:

  • 我正在使用 c++11,在 Range 链接之后给出的示例告诉我:erreur: 'type' 之前的预期嵌套名称说明符。它是 c++11 的合成器吗?
  • @user1595929 我不知道你到底在尝试什么。尝试分享您的代码。例如,在this example 中它工作得很好。是的,它是 C++11。
  • 我无法使 Range 代码正常工作。我想通了使用上面的 initializer_list 解决方案。
  • @user1595929 是的,这是正确的做法,而且要简单得多。我无法弄清楚,因为我不知道 array 是什么,scoped_ptr 是什么,.reset() 是什么意思,以及你真正想要做什么(初始化数组)。
猜你喜欢
  • 2016-04-09
  • 1970-01-01
  • 1970-01-01
  • 2021-10-01
  • 2016-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-06
相关资源
最近更新 更多