【问题标题】:Initialize tuple across inheritance tree跨继承树初始化元组
【发布时间】:2026-02-14 09:15:02
【问题描述】:

让 B 类成为 A 的基础:

class B
{
public:
    std::tuple<int, bool, float> properties.
}

class A : public B
{
public:
    std::tuple<float, std::string, std::string> derivedProperties.
}

有没有办法将派生属性元组添加到基础属性元组?例如通过某种形式的 CRTP?我知道基类和派生类型的属性在编译时是已知的,但我似乎无法弄清楚如何组合不同继承级别的属性。

【问题讨论】:

  • 至于你的问题,你可能有兴趣了解template parameter packs
  • 但是如何使用可变参数模板构造函数来确定基本成员元组的类型?
  • B 中的元组是否应该始终至少具有您显示的类型?并且您想添加更多字段(因此生成的 properties 元组将是 std::tuple&lt;int, bool, float, float, std::string, std::string&gt;?
  • 另外,您是否考虑过使用 struct 代替元组?因为派生类A 可以有自己的struct 继承自基类。
  • 对外界来说是的,我希望 B 类中的元组具有所有属性类型。

标签: c++ inheritance tuples


【解决方案1】:

您可以使用variadic templates 向基类的properties 成员(B) 添加更多类型。如果你希望派生类也有基类的构造函数,你可以使用using-declaration:

#include <string>
#include <tuple>

template<typename... Ts>
class B {
public:
    B(int i, bool b, float f, const Ts&... rest) :
            properties(std::make_tuple(i, b, f, rest...)) {
    }
    std::tuple<int, bool, float, Ts...> properties;
};

class A : public B<float, std::string, std::string> {
    using B::B;
};

int main() {
    A foo(12, true, 3.14, 6.28, "foo", "bar");
}

class B的派生类传递给同一个函数可以通过函数模板实现:

template<typename... Ts>
void test(const B<Ts...>& base);

Live Demo

【讨论】:

    【解决方案2】:

    如果相关,您可以使用以下内容:

    template <typename ... Ts>
    class C
    {
    public:
        std::tuple<int, bool, float, Ts...> properties.
    };
    
    using B = C<>;
    using A = C<float, std::string, std::string>;
    

    【讨论】:

      【解决方案3】:

      当您想到 CRTP 时,您差一点就接受了。

      您可以执行以下操作:

      // We need this boilerplate to overcome
      // the incompleteness of "Derived" when instantiating "Base<Derived>"
      template <typename T>
      struct properties {
          using type = std::tuple<>;
      };
      
      class Derived;
      
      template <>
      struct properties<Derived> {
          using type = std::tuple<float, std::string, std::string>;
      };
      
      // Now that we defined our properties
      template <typename Derived>
      class Base {
      public:
          using derived_properties_t = typename properties<Derived>::type; // Should be a tuple
          using base_properties_t = std::tuple<int, bool, float>;
          using combined_properties_t = decltype(std::tuple_cat(std::declval<base_properties_t>(),
                                                                std::declval<derived_properties_t>()));
          combined_properties_t properties;
      };
      
      class Derived : public Base<Derived> {
      public:
          using properties_type = std::tuple<float, std::string, std::string>;
      };
      

      您可以在 Coliru 上查看工作演示

      【讨论】: