【问题标题】:Cumbersome inheritance from template class从模板类继承繁琐
【发布时间】:2023-03-11 00:00:01
【问题描述】:

以下是具有某些功能的模板的代码。几个结构将从它继承,每个结构将使用不同的 UniqueTag。也就是说,每个结构都继承自一个唯一的模板。通过第 1 次天真的尝试,代码变得非常冗长。尝试 #2 在详细程度方面要好一些,但删除了能够通过模板实例化更改 UniqueTag 值的所需属性。 #3 的宏版本几乎没有让它变得更好。

我当然不是c++语法高手,这让我很纳闷:这个能不能表达的更清楚一点?

尝试 #1

template <int UniqueTag, typename Verbose, typename Arguments>
struct Base {
    static const int tag = UniqueTag;
    // Random example functionality
    float data_;
    Base(float data) : data_(data) {}
    int do_stuff(Verbose& v, Arguments& a) {
        return v + a;
    }
};

template <int UniqueTag, typename Verbose, typename Arguments> // once...
struct Foo : Base<UniqueTag, Verbose, Arguments> { // twice...
    typedef Base<UniqueTag, Verbose, Arguments> base_t; // thrice..!
    Foo(float data) : base_t(data) {}
    int do_it() {
        Verbose v(10);
        Arguments a(10);
        return base_t::do_stuff(v, a); // must qualify dependent class name
    }
};

尝试 #2

稍微更理智的方法是将模板参数存储在基类中。现在Foo 不必是模板类。它可以从模板继承并通过它引用类型,而没有依赖类的问题。 但它确实消除了Foo2 的模板性,这是不可接受的。

template <int UniqueTag, typename Verbose, typename Arguments>
struct Base2 {
    typedef Verbose verbose_t;
    typedef Arguments arguments_t;
    static const int tag = UniqueTag;
    float data_;
    Base2(float data) : data_(data) {}
    int do_stuff(Verbose& v, Arguments& a) {
        return v + a;
    }
};

typedef Base2<1, int, int> Foo2Base;
struct Foo2 : Foo2Base {
    Foo2(float data) : Foo2Base(data) {}
    int do_it() {
        verbose_t v(10);
        arguments_t a(10);
        return do_stuff(v, a);
    }
};

尝试 #3

上一个示例的宏版本也可以,但它仅节省了一行代码,同时使代码不那么明显。

#define BASE_MACRO(name, tag, typeA, typeB) \
    typedef Base2<tag, typeA, typeB> name ## Base; \
    struct name : name ## Base

BASE_MACRO(Foo3, 2, int, int) {
    Foo3(float data) : Foo3Base(data) {}
    int do_it() {
        verbose_t v(10);
        arguments_t a(10);
        return do_stuff(v, a);
    }
};

// To compile all of the above.
#include <iostream>
int main() {
    Foo<0, int, int> a(1.0);
    std::cout << a.do_it() << std::endl;
    Foo2 b(1.0);
    std::cout << b.do_it() << std::endl;
    Foo3 c(1.0);
    std::cout << c.do_it() << std::endl;
};

如果是这样的话,即使是明确的“没有更好的方式来表达这一点”也会有所帮助。

【问题讨论】:

  • 我不知道比问题中的那些更好的方法。

标签: c++ templates inheritance


【解决方案1】:

怎么样?

使 do_stuff 成为模板方法

template <int UniqueTag>
struct Base {
    static const int tag = UniqueTag;
    // Random example functionality
    float data_;
    Base(float data) : data_(data) {}
    template <typename Verbose, typename Arguments>
    int do_stuff(Verbose& v, Arguments& a) {
        return v + a;
    }
};

template <int UniqueTag, typename Verbose, typename Arguments> // once...
struct Foo : Base<UniqueTag> { // shorter reference
    typedef Base<UniqueTag> base_t; // shorter reference
    Foo(float data) : base_t(data) {}
    int do_it() {
        Verbose v(10);
        Arguments a(10);
        return base_t::do_stuff(v, a); // must qualify dependent class name
    }
};

保持 Foo 的模板性,同时减少冗长

【讨论】:

  • 我喜欢它。这让我更加纠结,我想出了一些可以使用/不使用这种方法的其他方法。
【解决方案2】:

经过一番折腾,我想出了自己的简化。只需将整个基类作为单个模板参数传递即可。

template <int UniqueTag, typename Verbose, typename Arguments>
struct Base {
    typedef Verbose verbose_t;
    typedef Arguments arguments_t;
    static const int tag = UniqueTag;
    float data_;
    Base2(float data) : data_(data) {}
    int do_stuff(Verbose& v, Arguments& a) {
        return v + a;
    }
};

template <typename Base>
struct Foo : Base {
    Foo(float data) : Base(data) {}
    int do_it() {
        typename Base::verbose_t v(10);
        typename Base::arguments_t a(10);
        return this->do_stuff(v, a);
    }
};

Foo<Base<5, int, int> > f(1.0);

可选地结合@jsantander 的回答,它应该在各种情况下都有帮助。

【讨论】:

    猜你喜欢
    • 2019-04-10
    • 2018-05-23
    • 2018-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-18
    相关资源
    最近更新 更多