【问题标题】:C++ nested templates structsC++ 嵌套模板结构
【发布时间】:2019-12-01 13:13:32
【问题描述】:

所以我对这样的代码有问题:

我有这样的结构

template <int N>
struct Inner
{
    enum
    {
        val = 2*N
    };
};

我想达到这样的目标:

int v = Outer<Inner<4>>::val;
int b = Outer<false>::val;
cout<< v <<endl;
cout<< b <<endl;

我的目标是创建“Outer”结构,它采用boolInner&lt;int N&gt; 并将Outer::val 设置为Inner::valbool 所以我创造了这样的东西(不工作):

template <bool B>
struct Outer
{
    enum
    {
        val = B
    };
};

template <Inner<int> I>
struct Outer
{
    enum
    {
        val = I::val
    };
};

这有什么问题以及如何解决? (我见过一些类似的问题,但仍然无法将其应用于我的问题)

【问题讨论】:

    标签: c++ templates metaprogramming template-meta-programming template-specialization


    【解决方案1】:

    您的代码中存在一些问题。

    首先:你定义了两个不同的Outer结构

    template <bool B>
    struct Outer
     { /* ... */ };
    
    template <Inner<int> I>
    struct Outer
     { /* ... */ };
    

    你不能。

    如果你愿意,你可以声明一个Outer 结构和两个specializations,但是你必须决定Outer 必须接收什么类型的模板参数。

    因为,看着你的需求,

    int v = Outer<Inner<4>>::val;
    int b = Outer<false>::val;
    

    你想在一种情况下传递一个类型(Inner&lt;4&gt;),在另一种情况下传递一个值。而你不能。

    您必须决定Outer 是否接收类型或值。在 C++17 之前,如果接收一个值,则必须确定该值的类型;从 C++17 开始,您可以将 Outer 声明为接收泛型类型的值(auto 作为值的类型)。

    问题:Inner&lt;int&gt; 的值不能是模板参数(但另请参阅 Michael Kenzel 的回答,它显示了基于模板值参数的可能 C++20 解决方案)。

    所以我看到的唯一解决方案(在 C++20 之前)是将 Outer 声明为接收类型

    template <typename>
    struct Outer;
    

    然后你可以为Inner 类型定义一个Outer 特化

    template <int N>
    struct Outer<Inner<N>>
     { enum { val = Inner<N>::val }; }; // or simply enum { val = N };
    

    对于bool 值,您必须将它们包装在一个类中;我建议(从 C++11 开始)使用标准类 std::integral_constant 和下面的定义 Outer 专业化

    template <bool B>
    struct Outer<std::integral_constant<bool, B>>
     { enum { val = B }; };
    

    用法如下

    int v = Outer<Inner<4>>::val;
    int b = Outer<std::integral_constant<bool, false>>::val;
    
    std::cout << v << std::endl;
    std::cout << b << std::endl;
    

    你也可以使用std::false_type定义b

    int b = Outer<std::false_type>::val;
    

    并且,从 C++17 开始,还有 std::bool_constantstd::integral_constant 的简写,表示 bool 值)

    int b = Outer<std::bool_constant<false>>::val;
    

    【讨论】:

      【解决方案2】:

      模板参数可以是类型、值(非类型)或模板[temp.param]。您要实现的目标需要您的模板Outer 具有可以是类型或值的参数。不幸的是,这是不可能的。

      你可以做的是将你的布尔值包装在一个类型中:

      template <bool b>
      struct InnerBoolean
      {
          static constexpr bool val = b;
      };
      

      然后对Outer有一个通用定义

      template <typename T>
      struct Outer
      {
          enum
          {
              value = T::val
          };
      };
      

      然后使用Outer&lt;Inner&lt;4&gt;&gt;Outer&lt;InnerBoolean&lt;False&gt;&gt;

      如果您将val 重命名为value,而不是编写自己的包装器,您可以使用标准库在std::bool_constantstd::true_typestd::false_type 中提供的包装器。

      在 C++17 之前,非类型模板参数不能是类类型 [temp.param]/4,C++20 将解除此限制并允许任何 literal type 的模板参数。因此,只要Inner 可以是文字类型,您就可以直接传递Inner 类型的值并使用自动模板参数:

      struct Inner
      {
          int N;
      
          constexpr Inner(int N) : N(N) {}
      
          constexpr operator int() const { return 2*N; }
      };
      
      template <auto val>
      struct Outer
      {
          enum
          {
              value = val
          };
      };
      
      auto a = Outer<Inner(4)>::value;
      auto c = Outer<false>::value;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-26
        • 2014-10-12
        • 2018-11-08
        • 2016-11-29
        • 1970-01-01
        相关资源
        最近更新 更多