如何在存在不可预测的类型别名时进行显式模板实例化?

问题描述 投票:14回答:4

我试图在我的项目中添加一些extern template,以加快构建时间并减少构建期间磁盘上的占用空间。

我是通过列出我经常使用的专业化来完成的,例如:

extern template class std::vector<std::string>;
extern template class std::vector<unsigned int>;
extern template class std::vector<uint32_t>;
extern template class std::vector<size_t>;

问题是unsigned intsize_t,也许,uint32_tunsigned int,也许。因此,根据构建目标,实际实例化特化的“非extern”列表的编译失败:

template class std::vector<std::string>;
template class std::vector<unsigned int>;
template class std::vector<uint32_t>;
template class std::vector<size_t>;

错误是这样的(行号和列号不准确):

templates-impl.h:15:36: error: duplicate explicit instantiation of ‘class std::vector<long unsigned int>’ [-fpermissive]
 template class std::vector<size_t>;

我的目标是能够列出我使用的类型,因为我使用它们,最小的麻烦,不需要为不同的目标硬编码列表的变体。

我想在C ++ 14中我可以使用if constexpr和一些std::is_same来解决这个问题,至少如果在命名空间范围内允许的话。

我怎么能在C ++ 11中做到这一点?

c++ c++11 templates extern
4个回答
7
投票

或者,您可能具有待实例化类型的类型列表,其中只有重复类型被替换为虚拟类型(希望在链接时优化)。

在C ++ 11中,类似于:

template<typename... V>
struct explicit_instlist
{
    template<int I>
    struct get
    {
        using VI = typename std::tuple_element<I,std::tuple<V...>>::type;

        using type = typename std::conditional< is_first_at<I,VI,V...>::value,
            VI, dummy_inst<I,VI> >::type;
    };
};

template<unsigned I>
using my_list = typename explicit_instlist<
    std::string,
    unsigned int,
    uint32_t,
    size_t
    >::template get<I>::type;

/*extern*/ template class std::vector< my_list<0> >;
/*extern*/ template class std::vector< my_list<1> >;
/*extern*/ template class std::vector< my_list<2> >;
/*extern*/ template class std::vector< my_list<3> >;

其中dummy_inst<I,T>生成一个独特的虚拟类型,用于代替T已经使用过,而is_first_at的工作方式如下:

template<int I,typename T>
struct dummy_inst {};

template<int I,typename T,typename... V>
struct is_first_at {};

template<int I,typename T,typename V,typename... Vs>
struct is_first_at<I,T,V,Vs...>: std::conditional< std::is_same<T,V>::value,
    std::integral_constant<bool,I==0>,
    is_first_at<I-1,T,Vs...> >::type {};

显然,如果要显式实例化的模板不支持空默认值,那么dummy_inst将需要专门化。像boost boost处理程序之类的东西可以用来避免明确地“迭代”显式瞬时并写一个直接接受类型列表的宏......


5
投票

如何删除unsigned int和size_t特化并使它们全部基于大小?

extern template class std::vector<uint8_t>;
extern template class std::vector<uint16_t>;
extern template class std::vector<uint32_t>;
extern template class std::vector<uint64_t>;

1
投票

我不确定extern是如何工作的,但如果它是显式实例化模板的问题,也许你可以使用这样的函数调用。类型复制不应生成错误。

template<class T>
void instance(T const&){std::vector<T> v{}; (void)v;}

void instantiate(){
   instance(std::string{}):
   instance(unsigned int{});
   instance(uint32_t{});
   instance(size_t{});   
}

(我不是说这是最好的方法。)


0
投票

这是一种方法:

#include <utility>
#include <type_traits>

template<typename T>
struct Test {};

template<typename... Ts>
struct types {};

template<template<typename>class Template, typename Types>
struct Instantiate {};

template<template<typename>class Template, typename T0, typename... Ts>
struct Instantiate<Template, types<T0, Ts...>>:
  Instantiate<Template, types<Ts...>>
{
  Template<T0>& unused();
};

template<typename U, typename Types>
struct prepend;

template<typename U, template<typename...>class pack, typename... Ts>
struct prepend< U, pack<Ts...> > {
  typedef pack<U, Ts...> types;
};
template<typename U, typename Types>
using Prepend = typename prepend<U, Types>::types;

template<typename U, typename Types, typename=void>
struct remove_type_from_types;
template<typename U, template<typename...>class pack>
struct remove_type_from_types<U, pack<>, void>
{
  typedef pack<> types;
};

template<typename U, template<typename...>class pack, typename T0, typename... Ts>
struct remove_type_from_types< U, pack<T0, Ts...>,
  typename std::enable_if< std::is_same<U, T0>::value >::type
>: remove_type_from_types< U, pack<Ts...> >
{};

template<typename U, template<typename...>class pack, typename T0, typename... Ts>
struct remove_type_from_types< U, pack<T0, Ts...>,
  typename std::enable_if< !std::is_same<U, T0>::value >::type
>
{
  typedef Prepend< T0, typename remove_type_from_types< U, pack<Ts...> >::types > types;
};

template<typename Types>
struct remove_duplicates {
  typedef Types types;
};

template<template<typename...>class pack, typename T0, typename... Ts>
struct remove_duplicates<pack<T0, Ts...>> {
private:
  typedef typename remove_type_from_types< T0, pack<Ts...> >::types filtered_tail;
  typedef typename remove_duplicates< filtered_tail >::types unique_tail;
public:
  typedef Prepend< T0, unique_tail > types;
};
template<typename Types>
using RemoveDuplicates = typename remove_duplicates<Types>::types;

static Instantiate<Test, RemoveDuplicates<types<int, double>> > unused;

可能的改进/替代方案

  • 做一个菊花链调用。然后在未被任何人调用的导出函数中调用底部函数。模板将被实例化以便导出该函数,稍后在链接时将删除导出的函数
  • 做一个总和sizeof
© www.soinside.com 2019 - 2024. All rights reserved.