【问题标题】:Repeatedly using non-type template parameter at block scope在块范围内重复使用非类型模板参数
【发布时间】:2020-03-03 13:39:28
【问题描述】:

我有以下sn-p的代码:

template <size_t N>
foo make() { ... }

...

for (...) {
    auto foo = make<1>();
    // lots of tests involving foo
}

我想用非类型模板参数的不同值重复后一个块到make,例如make&lt;2&gt;make&lt;3&gt;等。

如果这是我想要迭代的类型,我可以使用 this solution,但不清楚我是否可以以相同的方式将非类型模板参数与泛型 lambda 一起使用。

我怎样才能考虑到这一点,以便我可以创建运行上面的代码块,但用不同的值来实例化 make 的非类型参数。该解决方案应仅使用块范围元素 - 如果我可以创建一些顶级 template &lt;size_t N&gt; struct maker { ... } 对象来包装 make,这很容易。

【问题讨论】:

  • 那么,你有一个终止索引吗?您确定要从 1 而不是 0 开始吗​​?
  • @NicolBolas - 在这种情况下,我想从 1 开始,但如果 0 的解决方案更干净,我可以适应它。终止索引约为 10,但我也可以手动列出案例,例如 something { bar&lt;1&gt;, bar&lt;2&gt;, ... } 或其他(但不复制 for 循环中的所有代码)。

标签: c++ templates c++17


【解决方案1】:

在这种情况下,正确的工具是使用std::integer_sequence

#include <iostream>
#include <utility>

template <size_t N>
void make()
{
  std::cout << N << std::endl;
}

template <size_t... I>
void do_make_helper(std::index_sequence<I...>)
{
  (make<I+1>(), ...); 
}

template <std::size_t N>
void do_make()
{
  do_make_helper(std::make_index_sequence<N>());
}

int main()
{
  do_make<10>();
}

打印

1
2
3
4
5
6
7
8
9
10

【讨论】:

    【解决方案2】:

    作为手工索引列表的起点:

    template <size_t N> int make();
    
    template<> int make<1>() { std::cout<< "First" << std::endl; return 100; }
    template<> int make<2>() { std::cout << "Second" << std::endl; return 200; }
    template<> int make<3>() { std::cout << "Third" << std::endl; return 100; }
    
    struct ExecuteInOrder { ExecuteInOrder( ... ) {} };
    
    template < typename T>
    void CallTest(T t )
    {
        std::cout << "Your test code goes here...: " << t << std::endl;
    }
    
        template< size_t ... N >
    void Do()
    {
        ExecuteInOrder {(CallTest(make<N>()),1)...};
    }
    
    int main()
    {
        Do<1,2,3>();
    }
    

    或者您可以简单地使其递归并像这样使用 index first 和 last :

    template < size_t FIRST, size_t LAST >
    void ExecuteAndTest()
    {
        auto foo = make<FIRST>();
        std::cout << "Here we go with the test" << foo << std::endl;
    
        // go for next step
        if constexpr ( LAST != FIRST ) { ExecuteAndTest<FIRST+1, LAST>(); }
    }
    
    int main()
    {
        // first and last index of integer sequence
        ExecuteAndTest<1,3>();
    }
    

    最后总是从 1 到 N

        template < size_t FIRST, size_t LAST >
    void ExecuteAndTest_Impl()
    {   
        auto foo = make<FIRST>();
        std::cout << "Here we go with the test" << foo << std::endl;
    
        // go for next step
        if constexpr ( LAST!= FIRST) { ExecuteAndTest_Impl<FIRST+1, LAST>(); }
    }
    
        template < size_t LAST > 
    void ExecuteAndTest()
    {   
        ExecuteAndTest_Impl<1,LAST>();
    }   
    
    int main()
    {   
        // or always start with 1 to n inclusive
        ExecuteAndTest<3>();
    }  
    

    【讨论】:

      【解决方案3】:

      你可以试试这个:

      #include <utility>
      #include <cassert>
      
      struct Foo
      { 
          Foo() {}
          Foo(std::size_t i) : i(i) {}
          std::size_t i;
      };
      
      template <std::size_t... Is>
      void setFoo(std::size_t i, Foo& foo, std::index_sequence<Is...>)
      {
          ((i == Is && (foo = Foo{Is}, false)), ...);
      }
      
      int main()
      {
          for (std::size_t i = 0; i < 10; i++)
          {
              Foo foo;
              setFoo(i, foo, std::make_index_sequence<10>{});
              assert(foo.i == i);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-22
        • 1970-01-01
        • 2021-03-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多