在存在不可预测的类型别名的情况下如何处理显式模板实例化?
How to approach explicit template instantiation in the presence of unpredictable type aliases?
我正在尝试将一些 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 int
是size_t
,也许,uint32_t
是 unsigned int
,也许吧。因此,根据构建目标,"non-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 中实现?
放弃 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>;
或者,您可能有待实例化类型的类型列表,其中只有重复类型被替换为虚拟类型(希望在 link 时间优化掉)。
在 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 预处理器之类的东西来明确地避免 'iterating' 显式实例化并编写一个直接接受类型列表的宏 ...
这是一种方法:
#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;
可能 improvements/alternatives:
进行菊花链调用。然后在一个没有被任何人调用的导出函数中调用底部的那个。模板将被实例化以导出该函数,稍后在链接时将删除导出的函数
求和-sizeof
我不确定 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{});
}
(我并不是说这是最好的方法。)
我正在尝试将一些 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 int
是size_t
,也许,uint32_t
是 unsigned int
,也许吧。因此,根据构建目标,"non-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 中实现?
放弃 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>;
或者,您可能有待实例化类型的类型列表,其中只有重复类型被替换为虚拟类型(希望在 link 时间优化掉)。
在 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 预处理器之类的东西来明确地避免 'iterating' 显式实例化并编写一个直接接受类型列表的宏 ...
这是一种方法:
#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;
可能 improvements/alternatives:
进行菊花链调用。然后在一个没有被任何人调用的导出函数中调用底部的那个。模板将被实例化以导出该函数,稍后在链接时将删除导出的函数
求和-
sizeof
我不确定 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{});
}
(我并不是说这是最好的方法。)