打开包装清单

时间:2017-02-02 12:19:34

标签: c++ templates c++14 variadic-templates c++17

假设我有一个只接受类型模板参数的函数,我无法改变它的定义/实现。

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解决方案也是如此,但标记为这样。

2 个答案:

答案 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{} ); 
}

这允许您避免递归模板实例化,这通常更昂贵。

Live Demo

在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{} ); 
}

Live Demo

答案 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>一样。