问题描述
我是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");
...