调用带有类型名称组合的模板函数

huangapple go评论73阅读模式
英文:

Call template function with typename combinations

问题

我想循环遍历一个"类型名称列表",并查看它们的所有组合。我考虑使用元组来实现这一点,比较:

template<typename T, typename R>
void foo() {
    std::cout << std::numeric_limits<T>::max() << ", " << std::numeric_limits<R>::max();
}

void call() {
    using int_types = std::tuple<int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t>;
    // 只是为了可视化我的想法,这段代码不起作用!(请参见注释)
    constexpr auto indices = std::make_integer_sequence<size_t, 8>();
    for (auto i: indices) {
        using T = std::tuple_element_t<i, int_types>;
        for (auto j: indices) {
            using R = std::tuple_element_t<j, int_types>;
            foo<T, R>();
        }
    }
}

当然,for循环不是consteval,因此这种方法不起作用。我认为可以使用STL的递归或一些consteval功能来解决,但我还没有完全弄清楚。

英文:

I want to loop over a "list of typenames" and look at all combinations of them. I was thinking of using a tuple for this, compare:

template&lt;typename T, typename R&gt;
void foo() {
    std::cout &lt;&lt; std::numeric_limits&lt;T&gt;::max() &lt;&lt; &quot;, &quot; &lt;&lt; std::numeric_limits&lt;R&gt;::max();
}

void call() {
    using int_types = std::tuple&lt;int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t&gt;;
    //Just to visualize my idea, this code does not work! (see comments)
    constexpr auto indices = std::make_integer_sequence&lt;size_t, 8&gt;();
    for (auto i: indices) {
        using T = std::tuple_element_t&lt;i, int_types&gt;;
        for (auto j: indices) {
            using R = std::tuple_element_t&lt;j, int_types&gt;;
            foo&lt;T, R&gt;();
        }
    }
}

Of course for loops are not consteval, thus this approach does not work. I think it might work using recursion or some consteval stuff from the STL but I can't quite figure it out.

答案1

得分: 2

您可以以这种方式扩展包

使用 int_types = std::tuple<int8_t, uint8_t, int16_t, uint16_t,
int32_t, uint32_t, int64_t, uint64_t>;

[]<typename... Ts>(std::tuple<Ts...>){
[]<typename T, typename... Us>(std::type_identity, std::tuple<Us...>){
(foo<T, Us>(), ...);
}(std::type_identity{}, int_types{}), ...);
}(int_types{});

[演示](https://godbolt.org/z/K7K9q3hPG)
英文:

You can expand pack that way

using int_types = std::tuple&lt;int8_t, uint8_t, int16_t, uint16_t,
                             int32_t, uint32_t, int64_t, uint64_t&gt;;

[]&lt;typename... Ts&gt;(std::tuple&lt;Ts...&gt;){
    ([]&lt;typename T, typename... Us&gt;(std::type_identity&lt;T&gt;, std::tuple&lt;Us...&gt;){
        (foo&lt;T, Us&gt;(), ...);
    }(std::type_identity&lt;Ts&gt;{}, int_types{}), ...);
}(int_types{});

Demo

答案2

得分: 2

这是一个基于索引的版本,其中内部 lambda 函数可以访问具体的索引,比如 LK。在这个版本中,如果需要的话,你可以进行验证,例如,如果索引相等,你可以选择排除对 foo 的调用:

void call() {
   using int_types = std::tuple<int8_t, uint8_t, int16_t, uint16_t, int32_t,
                                uint32_t, int64_t, uint64_t>;

   constexpr auto tsize = std::tuple_size_v<int_types>;

   []<std::size_t... Is>(std::index_sequence<Is...>) {
      (  // 折叠 1
         []<size_t I, std::size_t... Js>(std::integral_constant<std::size_t, I>,
                                         std::index_sequence<Js...>) 
         {
            ( // 折叠 2:
               []<std::size_t K, std::size_t L>(
                   std::integral_constant<std::size_t, K>,
                   std::integral_constant<std::size_t, L>)
               {
                        
                  if constexpr(K != L) foo<std::tuple_element_t<K, int_types>,
                                           std::tuple_element_t<L, int_types>>();

               }(std::integral_constant<std::size_t, I>(),
                 std::integral_constant<std::size_t, Js>()),
               ...);

         }(std::integral_constant<std::size_t, Is>(),
           std::make_index_sequence<tsize>()),
         ...);
   }(std::make_index_sequence<tsize>());
}

演示

英文:

Here's an index based version where the inner lambda has access to the concrete indices, here L and K. In that you can do validation if you want to exclude calls to foo if the indices are equal for example:

void call() {
   using int_types = std::tuple&lt;int8_t, uint8_t, int16_t, uint16_t, int32_t,
                                uint32_t, int64_t, uint64_t&gt;;

   constexpr auto tsize = std::tuple_size_v&lt;int_types&gt;;

   []&lt;std::size_t... Is&gt;(std::index_sequence&lt;Is...&gt;) {
      (  // fold 1
         []&lt;size_t I, std::size_t... Js&gt;(std::integral_constant&lt;std::size_t, I&gt;,
                                         std::index_sequence&lt;Js...&gt;) 
         {
            ( // fold 2:
               []&lt;std::size_t K, std::size_t L&gt;(
                   std::integral_constant&lt;std::size_t, K&gt;,
                   std::integral_constant&lt;std::size_t, L&gt;)
               {
                        
                  if constexpr(K != L) foo&lt;std::tuple_element_t&lt;K, int_types&gt;,
                                           std::tuple_element_t&lt;L, int_types&gt;&gt;();

               }(std::integral_constant&lt;std::size_t, I&gt;(),
                 std::integral_constant&lt;std::size_t, Js&gt;()),
               ...);

         }(std::integral_constant&lt;std::size_t, Is&gt;(),
           std::make_index_sequence&lt;tsize&gt;()),
         ...);
   }(std::make_index_sequence&lt;tsize&gt;());
}

Demo

huangapple
  • 本文由 发表于 2023年2月23日 22:24:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/75546120.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定