【问题标题】:Variadic templates pack of a single templated class单个模板类的可变参数模板包
【发布时间】:2015-07-05 01:44:19
【问题描述】:

举个例子:

/* Signal Container */
template <typename Ret> class Signal;

template <typename Ret, typename... Args>
class Signal< Ret (Args...) >
{
    /* Following Implementation... */
};

/* Emitter Type */
template < template <typename Ret, typename... Args> Signal< Ret (Args...) > ... Sig>
class Emitter
{
    // using Signals = std::tuple<Sig...>;

    /* Following Implementation... */
};

/* Signals */
using Signal_A = Signal<void()>;
using Signal_B = Signal<void(int)>;
using Signal_C = Signal<void(int, float)>;

/* Desired Usage */
class MyType : public Emitter<Signal_A, Signal_B, Signal_C>
{

};

我希望能够从接受 1 个(0?)或多个 Signal 类型的模板参数的 Emitter 类型继承(并且只有 Signal)。 Signal 是一个模板类型,它的定义因传递给Emitter 参数包的每个类型而异。

我在 MinGW 上尝试了当前的方法,但收到这些错误消息,我有点迷茫:

/* Line: template < template <typename Ret, typename... Args> Signal< Ret (Args...) > ... Sig> */
main.cpp|15|error: expected 'class' before 'Signal'|


/* Line: template < template <typename Ret, typename... Args> Signal< Ret (Args...) > ... Sig> */
main.cpp|15|error: expected '>' before '<' token|


/* Line: class MyType : public Emitter<Signal_A, Signal_B, Signal_C> */
main.cpp|29|error: wrong number of template arguments (3, should be 1)|


/* Linne: class Emitter */
main.cpp|16|error: provided for 'template<template<class Ret, class ... Args> class Signal> class Emitter'|

如果有人能澄清这一点或提供可行的解决方案,我将不胜感激。

可用的编译器:MinGW GCC 4.9.2(也是 5.1.0)

【问题讨论】:

    标签: templates c++11 inheritance filtering variadic


    【解决方案1】:

    在 C++11 或 C++14 中,你不能以简单的方式做你想做的事。概念可能会给我们一些东西,但现在您的模板参数必须是类型、类模板或值。在您的情况下,您需要一组只能指定为的信号:

    template <typename... Sigs>
    class Emitter;
    

    在类中,您可以使用static_assert 来验证它们都是Signals:

    static_assert(all_true<is_signal<Sigs>::value...>::value, "Emitter must use only Signals");
    

    您必须为is_signal 编写一个类型特征,并为all_true 提供一个元函数。后者的一个例子可以在here找到。

    【讨论】:

    • 谢谢。这就是我最终的结果。我想要的只是对模板包中接收到的类型进行简单验证。
    【解决方案2】:

    您不必在类模板Emitter 中匹配Signal 的所有内部类型。您只需声明它是一个接收参数的模板。之后,您需要在您的应用程序中重复出现Signal&lt;T&gt; 的最小数量。假设最小值为 1,这里有一个解决方案。

    /* Signal Container */
    template <typename Ret>
    class Signal;
    
    template <typename Ret, typename... Args>
    class Signal<Ret(Args...)> {};
    
    /* Emitter Type */
    template <typename... Args>
    class Emitter;
    
    template <typename T>
    class Emitter<Signal<T> > {
        // definition of class with single signal
    };
    
    template <typename T, typename... Args>
    class Emitter<Signal<T>, Args...> {
        // definition of class with MORE THAN one signal
    };
    
    /* Signals */
    using Signal_A = Signal<void()>;
    using Signal_B = Signal<void(int)>;
    using Signal_C = Signal<void(int, float)>;
    
    /* Desired Usage */
    class MyType : public Emitter<Signal_A, Signal_B, Signal_C> {};
    
    int main() {
        MyType x;
    }
    

    【讨论】:

      【解决方案3】:

      我将其发布为答案,因为它确实满足问题中的要求。即使我标记了一个正确的答案。我认为发布我的最终方法是合适的。

      #include <iostream>
      
      /* Signal Container */
      template <typename Ret> class Signal;
      
      template <typename Ret, typename... Args>
      class Signal< Ret (Args...) >
      {
          /* Following Implementation... */
      };
      
      namespace {
          /* Signal Type Traits */
          template < typename T >
          struct IsSignal { static constexpr bool Value = false; };
      
          template < typename T >
          struct IsSignal< Signal< T > > { static constexpr bool Value = true; };
      
          /* Signal Validation */
          template < bool V, typename... Args >
          struct AreSignals
          {
              static constexpr bool Value = V;
          };
      
          template < bool V, typename T, typename... Args >
          struct AreSignals< V, T, Args... >
          {
              static constexpr bool Value = AreSignals< V && IsSignal< T >::Value, Args... >::Value;
          };
      
      }
      
      /* Emitter Type */
      template < typename... Args >
      class Emitter
      {
          // Block unsupported signals
          static_assert( AreSignals<true, Args...>::Value, "Unsupported signal type" );
      
          using Signals = std::tuple<Args...>;
      
          /* Following Implementation... */
      };
      
      using Signal_A = Signal<void()>;
      using Signal_B = Signal<void(int)>;
      using Signal_C = Signal<void(int, float)>;
      
      class MyType : public Emitter<Signal_A, Signal_B, Signal_C>
      {
      
      };
      
      int main(int argc, char **argv)
      {
          std::cout << AreSignals<true, Signal_A, Signal_B, Signal_C>::Value << "\n"; // 1 (true)
      
          std::cout << AreSignals<true, Signal_A, int, Signal_B, Signal_C>::Value << "\n"; // 0 (false)
      
          return EXIT_SUCCESS;
      }
      

      【讨论】:

        猜你喜欢
        • 2020-04-29
        • 2019-11-22
        • 1970-01-01
        • 1970-01-01
        • 2021-10-01
        • 1970-01-01
        • 2016-12-01
        • 2013-09-14
        • 1970-01-01
        相关资源
        最近更新 更多