在c++ 11中编写一个元函数,从类型列表返回一个类型,该类型列表具有给定类型的定义类型
Write a meta-function returning a type from a type-list that has a typedef of a given type in C++11
我遇到了这样一个场景,其中我在可变模板列表中有一个类列表,并且,给定一个类型(Target_
),我希望在列表(ContainingClass_
)中找到typedef
s Target_
作为ContainingClass_::Class
的类。
这是我目前的蛮力实现:
#include <iostream>
#include <cstdlib>
#include <type_traits>
#include <tuple>
template <uint32_t ID_, class Class_>
struct ContainingClass
{
using Class = Class_;
static constexpr uint32_t id() { return ID_; }
};
// Get the index of a type in a type list, or -1 on error (So that we only get the important static_assert).
template <typename Target_, typename ...List_>
struct IndexOf : std::integral_constant<int, -1> {};
template <typename Target_, typename NotTarget_, typename ...List_>
struct IndexOf<Target_, NotTarget_, List_...> : std::integral_constant<std::size_t, 1 + IndexOf<Target_, List_...>::value> {};
template <typename Target_, typename ...List_>
struct IndexOf<Target_, Target_, List_...> : std::integral_constant<std::size_t, 0> {};
// Check if a type exists in a typelist.
template <typename Target_, typename... List_>
struct TypeExists;
template <typename Target_>
struct TypeExists<Target_> : std::false_type {};
template <typename Target_, typename... List_>
struct TypeExists<Target_, Target_, List_...> : std::true_type {};
template <typename Target_, typename NotTarget_, typename... List_>
struct TypeExists<Target_, NotTarget_, List_...> : TypeExists<Target_, List_...> {};
// **THE META-FUNCTION THAT THE QUESTION IS ABOUT**
// Find the ContaingClass that typedefs Target_ as "Class" inside of it.
template <class Target_, class ...ContainingClasses_>
struct ContainingClassFinder
{
static_assert(TypeExists<Target_, typename ContainingClasses_::Class...>::value, "No ContainingClass found for Target_.");
using ContainingClass = typename std::tuple_element<IndexOf<Target_, typename ContainingClasses_::Class...>::value,
std::tuple<ContainingClasses_...>>::type;
};
using namespace std;
// Use the meta function to return the id of the ContainingClass that contains a type.
template <class Target_, class ...ContainingClasses_>
uint32_t get_containing_id(ContainingClasses_...)
{
return ContainingClassFinder<Target_, ContainingClasses_...>::ContainingClass::id();
}
struct Foo {};
struct Bar {};
struct Test {};
struct NonExistent {};
int main()
{
// Prove that the right class was found be printing its ID out.
// Prints 2.
cout << get_containing_id<Test>(ContainingClass<0, Foo>{}, ContainingClass<1, Bar>{}, ContainingClass<2, Test>{}) << endl;
// Causes static_assert.
//cout << get_containing_id<NonExistent>(ContainingClass<0, Foo>{}, ContainingClass<1, Bar>{}, ContainingClass<2, Test>{}) << endl;
return EXIT_SUCCESS;
}
这样做的问题是,它依赖于std::tuple
,并进行两次线性搜索:一次用于存在检查(使用第一个辅助元函数),另一次用于获取类型(使用std::tuple_element
)。
理想情况下,我希望一次完成所有这些,不需要两个辅助元函数和std::tuple
;这可行吗?如果没有,请对我的实现进行任何改进。
注意:
1。此元函数将用作库的实现细节;
2。元函数的结果应该是一个类型,特别是目标类型所在的包含类型。获取类的id()只是显示元函数正在工作的一种简单方法。
3。通过元函数,我指的是模板化的结构体,就像在<type_traits>
下面的解决方案如何?
没有std::tuple
,如果我没有错的话,只有一个线性搜索。
#include <iostream>
#include <cstdlib>
#include <type_traits>
template <uint32_t, class Class_>
struct ContainingClass
{ using Class = Class_; };
struct Foo {};
struct Bar {};
struct Test {};
template <typename, typename ...>
struct getContType;
template <typename T>
struct getContType<T>
{ using type = void; };
template <typename T, typename CC0, typename ... CCs>
struct getContType<T, CC0, CCs...>
{ using type = typename std::conditional<std::is_same<T,
typename CC0::Class>::value, CC0,
typename getContType<T, CCs...>::type>::type; };
int main()
{
static_assert(std::is_same<ContainingClass<2, Test>,
getContType<Test, ContainingClass<0, Foo>,
ContainingClass<1, Bar>, ContainingClass<2, Test>>::type
>::value, "!");
return EXIT_SUCCESS;
}
[Update] This is working for me:
// marker for not-found types
struct none {
};
// fwd declaration
template <typename Target_,typename ...List_> struct scanner;
template <
typename Target_,
typename Head_, typename ...List_
>
struct scanner<Target_, Head_, List_...> {
using found_type=typename std::conditional<
std::is_same<Target_, Head_>::value, // or any other predicate
Head_,
// if not, search further
typename scanner<Target_, List_...>::found_type
>::type;
// were are going to reset it anyway if in the end the found_type==none
static constexpr int value=
std::is_same<Target_, Head_>::value
? 0
: scanner<Target_, List_...>::value+1
;
};
// need a recursion stopper for the scanner here.
template <typename Target_>
struct scanner<Target_> {
using found_type=none;
// were are going to reset it anyway if in the end the found_type==none
static constexpr int value=-1;
};
template <typename Target, typename... List>
struct ContainingClassFinder {
private:
using result=scanner<Target, List...>;
public:
static constexpr int value=
std::is_same<typename result::found_type, none>::value
? -1
: result::value
;
using found_type=typename std::enable_if<
false==std::is_same<typename result::found_type, none>::value,
typename result::found_type
>::type;
};
/// brief test
struct dummy {
};
using good=ContainingClassFinder<
int,
long, dummy, int, char
>;
static_assert(std::is_same<int, good::found_type>::value, "Oops - good type failing");
static_assert(good::value==2, "Oops - good index failing");
using bad_notfound=ContainingClassFinder<
int,
long, dummy, float, char
>;
static_assert(bad_notfound::value==-1, "Ooops - bad type failing index");
// this should create a compilation error due to std::enable_if with a false condition
using non_existing=typename bad_notfound::found_type; // yeap, it does cause compilation error
相关文章:
- 使用简单类型列表实现的指数编译时间.为什么
- 从类型列表中递归删除重复项会导致编译器堆空间错误 (VS2017)
- 测试两个类型列表中的所有组合
- 谷歌测试:模板模板的笛卡尔乘积的类型列表与模板
- 在迭代模板类型列表时无法停止递归
- 将可变参数类型列表的扩展打包为复杂类型的初始值设定项列表 - 合法吗?
- 阅读从 istream 到矢量的不同类型列表
- 如何在C++中创建类型列表的 n 路笛卡尔积?
- c++17通过生成预先声明的类型列表的笛卡尔乘积来生成std::变体
- 将变量模板限制为类型列表
- 我可以使用特征指定变体的类型列表吗?
- 如何对要用于模板参数的类型列表进行编码
- 创建类型列表并访问每种类型的静态成员?
- 为什么BOOST :: HANA :: EXAREMIS ::键入实验功能?类型列表的棘手是什么
- 如果创建支持返回可变参数类型列表的通用模板 API,我应该使用 std::tuple 还是其他东西?
- std::仅移动类型列表:不能在 VC++ 中放入 std::vector
- C++类型列表创建子列表
- 调用STD ::功能,并带有变体类型列表
- 在没有宏的情况下在 C++98 中创建类型列表时遇到问题
- 如何从类型列表重建参数包