【问题标题】:How can I access the types in a C++ template parameter pack?如何访问 C++ 模板参数包中的类型?
【发布时间】:2020-04-20 07:47:15
【问题描述】:

我想构造一个类来表示从I 类型的值到O 类型的值的映射。 我创建了这个界面:

template <typename I, typename O> class Transform {
public:
    virtual O transform(I i) = 0;
};

接下来,我想让Transform 对象组合成一种“管道”转换:

template <typename X, typename Y, typename Z> class MergeTransform : public Transform<X, Z> {
private:
    Transform<X, Y> *first;
    Transform<Y, Z> *second;
public:
    MergeTransform(Transform<X, Y> *first, Transform<Y, Z> *second) {
        this->first = first;
        this->second = second;
    }
    Z transform(X x) {
        return second->transform(first->transform(x));
    }
};

目前困扰我的是试图弄清楚如何使用模板来合并任意数量的转换。我想做类似的事情

template <typename A, typename B, typename C> Transform<A, C> *merge(Transform<A, B> *t1, Transform<B, C> *t2) {
    return new MergeTransform(t1, t2);
}
template <typename A, typename... Bs, typename C> Transform<A, C> *merge(/* what should go here? */) {
    // ...
}

但是我不知道如何在第二个 merge 方法中表示来自 A-&gt;B1, B1-&gt;B2, B2-&gt;...-&gt;Bn, Bn-&gt;C 的 Transforms 列表。 我还考虑过让模板参数成为转换本身,即。

/*
 * assume A and B are Transforms
 */
template <typename A, typename B> /* some return Transform type here */ *merge(A *a, B *b) {
    return new MergeTransform(a, b);
}
template <typename A, typename... Bs, typename C> /* return type */ *merge(A *a, Bs... bs, C *c) {
    return merge(merge(a, bs), c);
}

但在不知道 A 和 B Transforms 的模板类型的情况下无法定义返回类型。有没有办法访问这些值?理想情况下,我可以说

template <Transform<X, Y> A, Transform<Y, Z> B> Transform<X, Z> *merge(A *a, B *b) {
    return new MergeTransform(a, b);
}
template <Transform<W, X> A, Transform<?, ?>... Bs, Transform<Y, Z> C> Transform<W, Z> *merge(A *a, Bs... *bs, C *c) {
    return merge(merge(a, bs), c);
}

如果merge(a, bs) 的扩展没有返回Transform&lt;X, Y&gt;,编译器会抛出错误。最好的方法是什么?

【问题讨论】:

标签: c++ templates variadic-templates variadic-functions


【解决方案1】:

由于滥用运算符重载和折叠表达式 (C++17),您可能会执行类似的操作来链接操作:

template <typename ... Fs>
class Chain
{
private: 
    template <typename F>
    struct CallerWrap
    {
        F f;
        CallerWrap(F f) : f(f) {}

        template <typename T>
        friend decltype(auto) operator+ (const CallerWrap& callerWrap, T&& x)
        {
            return callerWrap.f(std::forward<T>(x));
        }
    };

    std::tuple<Fs...> tup;  
public:

    Chain(Fs... fs) : tup{fs... }{}

    template <typename T>
    decltype(auto) operator()(T x) const {
        return std::apply([&x](auto... fs){ return (CallerWrap{fs} + ... + x); }, tup);
    }

};

Demo

f1(f2(f3(x))) 没有折叠表达式,但 f1 + (f2 + (f3 + x))(和其他二元运算符)有折叠表达式。 所以我们添加 wrapper 来使用后者,和前者是等价的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-07
    • 1970-01-01
    • 1970-01-01
    • 2018-07-27
    • 2014-07-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多