2013-06-18 28 views
4

如果我有一个类:忽略重复模板类的显式实例在C++

template <typename T> 
class MyClass 
{ 
// ... 
}; 

,我明确实例是:

template class MyClass<int>; 
template class MyClass<int>; // second time 

我得到一些编译器错误(铛例如,但不在VC++ 2010上)。我为什么要这样做?那么在某些情况下,T可能是另一种类型的typedef

template class MyClass<my_type_1>; 
template class MyClass<my_type_2>; 

有了一定的编译选项,my_type_1相同my_type_2而在其他情况下,它是不同的。我如何确保以上所有场景都能编译?有没有办法忽略重复实例?

+0

我个人在头文件中保存模板代码,并让编译器根据需要自动实例化它。我想在某些情况下,尽管会扩大编译时间。 – Dave

回答

2

您可以为您的配置定义预处理器标志,然后将模板放入#ifdef块中。

+0

这是很多定义!有时这些类型不是由配置定义的,而是可以一路改变。例如,最近,另一个类使用的某个'TextureCoord'类型是'Vec2f'的'typedef',但被更改为'Vec3f'(已经实例化),导致XCode发生编译错误。 – Samaursa

3

不专门针对typedefs,而是专门针对相关的基础类型(如int)。这样,您可以按照您喜欢的方式尽可能多/多次键入定义,并且始终可以获得所需的专业化。

+0

这不是一个坏建议,但是击败了'typedef'的目的。如果类型发生变化,我会得到链接错误,至少需要几分钟才能找出结果。 (比我现在好得多)(+1)。 – Samaursa

3

你可以找到另一种方式来显式实例化template,你可以对它进行元编程。

然后,不要每行都做一个实例化,请将它们全部做成一个包。对它们运行一个n^2算法(在编译时)以消除重复(或者,老实说,你可能会跳过:取决于你如何实例化模板,它可能不在意)。

事情是这样的,假设Instantiate< Template, types< blah, foo, bar > >实际实例传递作为第一个参数中的模板列表:

#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; 

int main() { 

} 

如前所述,你也许可以与整个消除,重复位做掉,因为如何我正在实例化使用template。我也不确定每个template的上述用法是否足以实例化它(即,它不会被优化掉,并且符号将被导出)。我怀疑Fancier独特类型的去除是很困难的,这对于任何合理数量的类型来说都足够浅和足够快,我们认为,类型数量递归深度为n,并且总共完成的工作量为n^2。 ,由于缺乏裸体类型的弱排序......)

+0

非常有趣。我也不确定这个模板在'Instantiate'结构中是否足够用于显式实例化。我无法访问“C++ 11”编译器,因此我无法测试它,但肯定会将其保存下来供以后学习。相当聪明的做法! – Samaursa

+0

@samaursa如果'template'的使用不够,请进行菊花链调用。然后在一个不被任何人调用的导出函数中调用最底层的函数。 'template's将被实例化以便导出该函数,并且稍后在链接中导出的函数将被消除,但是'template's可能不会在其他地方使用... – Yakk

+0

我试过使用C++ 11,并且显然不起作用。实例化中的引用显然不执行显式实例化。好主意,但。我也在寻找一个解决方案,使用宏非常无聊,对我的使用来说效率不高。 – brahmin