假设我有一个只接受类型模板参数的函数,我无法改变它的定义/实现。
template < typename T >
void do_it();
现在我有一个通常的方式定义的类型列表,不能改变它:
template< typename ...Ts >
struct typelist;
我想实现一个带有类型列表的函数,并在每种类型上运行do_it():
template< typename List >
void do_them();
我找到的唯一解决方案是:
template< typename T >
void do_them_impl()
{
do_it<T>();
}
template< typename T, typename Ts...>
void do_them_impl()
{
do_it<T>();
do_them_impl<Ts...>();
}
template< template < typename...> class List, typename ...Ts >
void do_them_extract( List<Ts...>&& )
{
do_them_impl< Ts >();
}
template< typename List >
void do_them()
{
do_them_impl( List{} );
}
但是,对于我希望创建单个do_them
函数的每种情况,这需要4个(!)函数。我将需要其中的一些,而且我不想为每个函数编写四个函数。我错过了什么吗?
C ++ 14欢迎,C ++ 17解决方案也是如此,但标记为这样。
答案 0 :(得分:7)
在C ++ 14中,您可以使用一些可怕的技巧来引入有效的包扩展上下文:
template< template < typename...> class List, typename ...Ts >
void do_them_impl( List<Ts...>&& )
{
(void)std::initializer_list<int> {
(do_it<Ts>(), 0)...
};
}
template< typename List >
void do_them()
{
do_them_impl( List{} );
}
这允许您避免递归模板实例化,这通常更昂贵。
在C ++ 17中,您可以使用fold expressions:
template< template < typename...> class List, typename ...Ts >
void do_them_impl( List<Ts...>&& )
{
(do_it<Ts>(), ...);
}
template< typename List >
void do_them()
{
do_them_impl( List{} );
}
答案 1 :(得分:0)
这是一个利用C ++ 14的通用lambdas的解决方案:
template <typename T>
struct type_ { using type = T; };
template <typename Type>
using type = typename Type::type;
template <typename List>
struct map_;
template <template <typename...> typename Container, typename... Ts>
struct map_<Container<Ts...>>
{
template <typename Fun>
void operator()(Fun&& fun)
{
(void)((int[sizeof...(Ts)]){(fun(type_<Ts>{}), 0)...});
}
};
template <typename List>
auto map = map_<List>{};
然后为每个功能
#include <iostream>
#include <cxxabi.h>
#include <typeinfo>
template <typename T>
const char * type_name()
{
return abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, nullptr);
}
template <typename T>
void do_it()
{
std::cout << type_name<T>() << std::endl;
}
你可以写:
template <typename List>
void do_them()
{
map<List>([](auto v){ do_it<type<decltype(v)>>(); });
}
template <typename... Ts>
struct typelist {};
int main()
{
do_them<typelist<int, char, bool>>();
return 0;
}
使用-O3进行编译会给出相同的程序集,就好像我们只是连续调用do_it<int>
,do_it<char>
,do_it<bool>
一样。