【问题标题】:Static inheritance with variadic templates可变参数模板的静态继承
【发布时间】:2020-10-17 22:18:42
【问题描述】:

我正在尝试使用std::conditional 来实现静态继承。 我的child 类有两个可能的父类,parent_one,它应该根据传递的类型保存多个变量,parent_two,它有两种类型。我正在使用标签调度来区分我想要继承的类。

现在解决问题。当我调用child 并将其标记为从parent_one 继承两种类型时,它按预期工作。但是,如果我尝试将任意数量的类型传递到 child 以从 parent_one 继承,则会出现错误:

static_polymorphism.cpp: In instantiation of ‘class child<foo_type, int, int, double, float>’:
static_polymorphism.cpp:110:41:   required from here
static_polymorphism.cpp:99:7: error: wrong number of template arguments (4, should be 2)
   99 | class child : public std::conditional_t<
      |       ^~~~~
static_polymorphism.cpp:90:7: note: provided for ‘template<class T, class F> class parent_two’
   90 | class parent_two {
      |       ^~~~~~~~~~
static_polymorphism.cpp: In function ‘int main(int, char**)’:
static_polymorphism.cpp:111:9: error: ‘class child<foo_type, int, int, double, float>’ has no member named ‘log’
  111 |   first.log();

如果我理解正确,编译器应该根据我的标签调度生成代码。这意味着它应该从parent_one 创建重载类 - N(基于传递的类型)和来自parent_two 的M(基于传递的类型)。但是由于某种原因,我不知道,它不接受类型的变量计数。你能告诉我我做错了什么吗?

实施就在这里。

using one_t = struct foo_type{};
using two_t = struct bar_type{};

template <typename ... TYPES>
class parent_one {
public:
  parent_one() = default;
  void log() {
    std::cout << "parent_one" << std::endl;
  }
};

template <typename T, typename F>
class parent_two {
public:
  parent_two() = default;
  void log() {
    std::cout << "parent_two" << std::endl;
  }
};

template <typename T, typename ... ARGS>
class child : public std::conditional_t<
    std::is_same_v<T, one_t>,
    parent_one<ARGS...>,
    parent_two<ARGS...>
  >
{
public:
  child() = default;
};

int main(int argc, char *argv[]) {
  child<one_t, int, int, double, float> first;
  first.log();

  child<two_t, int, int> second;
  second.log();
  return 0;
}

【问题讨论】:

    标签: c++ templates variadic


    【解决方案1】:
    std::conditional_t<
        std::is_same_v<T, one_t>,
        parent_one<ARGS...>,
        parent_two<ARGS...>
    >
    

    在检查条件之前,这两个备选方案都已验证。 std::conditional_t 并不神奇,它只是一个常规模板,它需要所有模板参数都有效才能执行任何操作。

    您需要延迟将模板参数替换到父模板中,直到选择了其中一个选项。这是一种可能的解决方案:

    template <template <typename...> typename T>
    struct delay
    {
        template <typename ...P>
        using type = T<P...>;
    };
    // ...
    class child :
        public std::conditional_t<
            std::is_same_v<T, one_t>,
            delay<parent_one>,
            delay<parent_two>
        >::template type<ARGS...> 
    {
        // ...
    };
    

    【讨论】:

    • 不错。我觉得这可以与type_identity 一起使用,但它似乎对我不起作用。你觉得这样可行吗?
    • @cigien 我希望它会遇到同样的问题。不过像template &lt;template &lt;typename...&gt; typename T, typename ...P&gt; struct delay {using type = T&lt;P...&gt;;}; 这样的东西应该可以工作。
    • 啊,是的,确实如此 :) type_identity 的问题是它不接受模板模板参数。
    • 谢谢,它有效。你能解释一下struct delay到底发生了什么吗?该类型接受类型 T 并将类型数组传递给类型,但是 template &lt;template &lt;typename...&gt; typename T&gt; 是什么意思?
    • @JirkaZahradnik 表示T 参数是一个模板(带有任意数量的类型参数)而不是特定类型。
    【解决方案2】:

    你可能很经典:

    template<class T, class... Args> struct child: parent_one<Args...> {};
    
    template<class T, class A, class B> struct child<T, A, B>: parent_two<A, B> {};
    
    template<class A, class B> struct child<one_t, A, B>: parent_one<A, B> {};
    

    (两个专业可以与requires (!std::is_same_v&lt;T, one_t&gt;)合二为一)。

    【讨论】:

    • 这确实解决了conditional_t 的问题,但是现在你有了专业化,这意味着该类必须至少实现两次?
    猜你喜欢
    • 2015-11-10
    • 1970-01-01
    • 1970-01-01
    • 2014-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-25
    相关资源
    最近更新 更多