知道其参数位置的C ++模板

问题描述

我是c ++元编程的新手,几天前,我决定编写一个带有可变参数包的模板,该模板知道参数包中哪个位置最先int。更准确地说,我想拥有一个struct,其名称 GetIntPos ,并带有static constexpr int value ,该值指示{{1}参数包中的}以1开头,如果参数包中没有int参数类型,则为0。例如

int

cout<<GetIntPos<long,char,int,long>::value; // must print 3
cout<<GetIntPos<int,long>::value; // must print 1

怎么办?

解决方法

使用模板类型特征实际上很简单:

#include <type_traits> // std::integral_constant
#include <cstddef>     // std::size_t

// Recursive base template (specialized below)
template <std::size_t Current,typename T,typename...Types>
struct find_type_aux;

// Specialization: If we find a match
template <std::size_t Current,typename...Types>
struct find_type_aux<Current,T,Types...>
  : std::integral_constant<std::size_t,Current>
{};

// Specialization: If we haven't found a match,but still have some left in the pack
template <std::size_t Current,typename Type0,Type0,Types...>
  : find_type_aux<Current + 1,Types...> // Strip off first,and search rest. Increment count
{};

// Specialization: If we didn't find a match
template <std::size_t Current,typename T>
struct find_type_aux<Current,T>
  : std::integral_constant<std::size_t,static_cast<std::size_t>(-1)>{};
{};

// The interface: Find's "T" and returns the 0-based index.
template <typename T,typename...Types>
struct find_type : find_type_aux<0u,Types...>{};

具有这样的特征,找到的元素将是从0开始的索引,而未找到的将是static_cast<std::size_t>(-1) 1

由于您提到被0索引为未找到,因此使用find_type<int,Types...>::value + 1会产生0(如果未找到(由于溢出))或1索引的结果-根据要求。


1 未被明确定义为1索引的原因是,可以重用当前定义以查找可变参数包中任何类型的索引-以及大多数使用包含变量的类型期望索引为0(例如std::get)。可以很容易地将其用作int的构建基块,例如使用可变模板:

template <typename...Types>
constexpr auto find_int_v = find_type<int,Types...>::value + 1;

然后从中得出正确的答案

int main() {
    std::cout << find_int_v<short,long,char> << '\n';
    std::cout << find_int_v<int,short,char> << '\n';
    std::cout << find_int_v<short,char,int> << '\n';
    return 0;
}

0
1
4
,

这似乎在我的测试中有效:

namespace detail {
    template <int INDEX>
    constexpr int GetIntPosImpl() {
        return 0;
    }

    template <int INDEX,typename ...Ts>
    constexpr int GetIntPosImpl() {
        if constexpr(std::is_same_v<T,int>) {
            return INDEX;
        }
        else {
            return GetIntPosImpl<INDEX + 1,Ts...>();
        }
    };
}

template <typename ...Ts>
struct GetIntPos {
    static constexpr int value = detail::GetIntPosImpl<1,Ts...>();
};

int main() {
    std::cout << GetIntPos<short,char>::value << '\n';
    std::cout << GetIntPos<int,char>::value << '\n';
    std::cout << GetIntPos<short,int>::value << '\n';
    return 0;
}

我的输出:

0
1
4
,

我的非递归方式(只是为了好玩...或代码模糊上下文)

#include <iostream>
#include <algorithm>
#include <type_traits>

template <int = 0>
auto GIP_helper (std::index_sequence<>)
   -> std::integral_constant<std::size_t,0u>;

template <typename ... Ts,std::size_t ... Is>
auto GIP_helper (std::index_sequence<Is...>)
   -> std::integral_constant<std::size_t,(1u+std::min({(std::is_same<Ts,int>::value
                      ? Is
                      : sizeof...(Is))...})) % (1u+sizeof...(Is))>;

template <typename ... Ts>
using GetIntPos
   = decltype( GIP_helper<Ts...>(std::index_sequence_for<Ts...>{}) );

int main()
 {
   std::cout << GetIntPos<long,int,long>::value << std::endl; 
   std::cout << GetIntPos<int,long>::value << std::endl;
   std::cout << GetIntPos<long,char>::value << std::endl;
 }

从C ++ 14开始工作。

,

我的递归方式

#include <iostream>
#include <type_traits>

template <std::size_t,typename ...>
struct GIP_helper
   : public std::integral_constant<std::size_t,0u>
 { };

template <std::size_t N,typename T0,typename ... Ts>
struct GIP_helper<N,T0,Ts...>
   : public GIP_helper<N+1u,Ts...>
 { };

template <std::size_t N,Ts...>
   : public std::integral_constant<std::size_t,N>
 { };


template <typename... Ts>
struct GetIntPos : public GIP_helper<1u,Ts...>
 { };

int main()
 {
   std::cout << GetIntPos<long,char>::value << std::endl;
 }

从C ++ 11开始工作。

,

这是使用Boost.MP11的解决方案:

var core_js_modules_es_array_includes__WEBPACK_IMPORTED_MODULE_166__ = __webpack_require__("../node_modules/core-js/modules/es.typed-array.includes.js");
...