从派生类引用基类的更好的习惯用法?

时间:2016-03-07 14:55:16

标签: c++ inheritance idioms self-reference idiomatic

假设我有一个

template <typename T>
class A : 
    class_with_long_name<T, and_many_other, template_arguments, oh_my_thats_long>,
    anotherclass_with_long_name<and_many_other, template_arguments_that, are_also_annoying, including_also, T> { ... }

现在,在A类的定义和/或其方法中,我需要引用两个超类(例如,访问超类中的成员,或者在其中定义的类型等)。但是,我想要避免重复超类名称。目前,我所做的是:

template<typename T>
class A : 
    class_with_long_name<T, and_many_other, template_arguments, oh_my_thats_long>,
    anotherclass_with_long_name<and_many_other, template_arguments_that, are_also_annoying, including_also, T> 
{
    using parent1 = class_with_long_name<T, and_many_other, template_arguments, oh_my_thats_long>;
    using parent2 = anotherclass_with_long_name<and_many_other, template_arguments_that, are_also_annoying, including_also, T>;
    ...
 }
显然,

有效,并将重复次数减少到2;但如果可能的话,我宁愿避免这种重复。有合理的方法吗?

注意:

  • &#34;合理&#34;例如没有宏,除非有非常好的理由。

5 个答案:

答案 0 :(得分:6)

在A之前,您可以

namespace detail
{
    template <typename T>
    using parentA1 = class_with_long_name<T,
                                          and_many_other,
                                          template_arguments,
                                          oh_my_thats_long>;
    template <typename T>
    using parentA2 = anotherclass_with_long_name<and_many_other,
                                                 template_arguments_that,
                                                 are_also_annoying,
                                                 including_also,
                                                 T>;
}

然后

template<typename T>
class A : detail::parentA1<T>, detail::parentA2<T>
{
};

答案 1 :(得分:1)

我认为,最好的选择就是你已经在做的事情。然而,如果你觉得你绝对不能容忍这一点,这里有一些有趣的代码(如果我在生产代码审查期间会看到这样的东西,我会煞费苦心地去除它)。

template<class... INHERIT_FROM> 
struct inherit_publicly : public INHERIT_FROM... {
    struct parent_types {
        template <int N, class ARG, class... ARGS> struct get {
            using type = typename get<N-1, ARGS...>::type;
        };
        template <class ARG, class... ARGS> struct get<0, ARG, ARGS...> {
            using type = ARG;
        };
    };

    template <int N> using parent = typename parent_types::template get<N, INHERIT_FROM...>::type;

};

// **example usage** 

struct X { static constexpr const char* const name = "X"; };
struct Y { static constexpr const char* const name = "Y"; };
struct Z { static constexpr const char* const name = "Z"; };


#include <iostream>

struct A : inherit_publicly<X, Y, Z> {
    void print_parents() {
        std::cout << "First parent type: " << parent<0>::name << "; second: " << parent<1>::name << "; third: " <<parent<2>::name<< "\n";
    }
};

int main() {
    A a;
    a.print_parents();
}

现场演示:http://coliru.stacked-crooked.com/a/37cacf70bed41463

答案 2 :(得分:1)

如果您使用相同的访问说明符继承所有类,则可以使用以下内容:

template <typename...S>
struct Bases : public S... {
    template <size_t I>
    using super = typename std::tuple_element<I, std::tuple<S...>>::type;
};

这将允许您按照从super<index>继承的顺序访问所有基类。

简短的例子:

#include <iostream>
#include <tuple>


template <typename...S>
struct Bases : public S... {
    template <size_t I>
    using super = typename std::tuple_element<I, std::tuple<S...>>::type;
};


class Foo
{
public:
    virtual void f()
    {
        std::cout << "Foo";
    }
};

class Fii
{
public:
    virtual void f()
    {
        std::cout << "Fii";
    }
};

class Faa : private Bases<Foo, Fii>
{
public:
    virtual void f()
    {
        std::cout << "Faa";
        super<0>::f(); //Calls Foo::f()
        super<1>::f(); //Calls Fii::f()
        std::cout << std::endl;
    }
};



int main()
{
    Faa faa;
    faa.f(); //Print "FaaFooFii"
    return 0;
}

答案 3 :(得分:1)

您可以使用A::class_with_long_nameA::anotherclass_with_long_name

template<typename T>
class A 
    : class_with_long_name<T, and_many_other, template_arguments, oh_my_thats_long>
    , anotherclass_with_long_name<and_many_other, template_arguments_that, are_also_annoying, including_also, T> 
{
    // If you still want the typedefs.
    using parent1 = typename A::class_with_long_name;
    using parent2 = typename A::anotherclass_with_long_name;

    // If you don't.
    void foo() { A::class_with_long_name::bar(); }
};

答案 4 :(得分:0)

基于@Jarod的解决方案:内部详细信息子名称空间如何?

namespace detail { namespace A {
    template <typename T>
    using parent1 = class_with_long_name<T,
                                          and_many_other,
                                          template_arguments,
                                          oh_my_thats_long>;
    template <typename T>
    using parent2 = anotherclass_with_long_name<and_many_other,
                                                 template_arguments_that,
                                                 are_also_annoying,
                                                 including_also,
                                                 T>;
} // namespace A
} // namespace detail

然后

template<typename T>
class A : detail::A::parent1<T>, detail::A::parent2<T>
{
};