忽略C ++中模板类的重复显式实例化

时间:2013-06-18 17:21:10

标签: c++ templates c++03

如果我有课:

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

我明确地实例化了它:

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

我在某些编译器上遇到错误(例如Clang,但在VC ++ 2010上没有)。我为什么要这样做?好吧,在某些情况下,T可能是typedef到另一种类型。

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

对于某些构建选项,my_type_1my_type_2相同,在其他情况下则不同。我如何确保以上编译在所有情况下?有没有办法忽略重复的实例化?

5 个答案:

答案 0 :(得分:4)

您可以找到另一种方法来显式实例化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的上述用法是否足以实例化它(即,它不会以某种方式被优化掉,并且符号将被导出)。

(类型数量的递归深度为n,完成的工作总数为n^2类型数量:对于任何合理数量的类型而言足够浅且足够快,我怀疑.Fancier独特的类型去除很困难,因为裸体类型缺乏弱排序......)

答案 1 :(得分:3)

不要专门针对typedef,而是专门针对相关的底层类型(例如int)。这样你就可以根据需要多次/多次输入def,你仍然可以获得你想要的专业。

答案 2 :(得分:2)

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

答案 3 :(得分:0)

Yakk救了我的日子。实际上我有很多非类型模板函数,其参数在编译时计算取决于某些&#34; #define&#34; s。我事先不知道他们的价值观,我想明确地实例化它们。但是当它们发生冲突时,编译器将停止并显示错误&#34;复制...&#34;。所以我遵循了Yakk的想法,我制作了一个非常简单的版本。我在这里发布可能感兴趣的人。

文件1:instantiate.h

npm start

文件2:instantiate.cpp

Module build failed: SyntaxError: Unexpected token (4:2)

  2 | 
  3 | export default class TodoModel {
> 4 |   @observable title;
    |   ^
  5 |   @observable finished = false;
  6 | 
  7 |   constructor(title) {

文件3:main.cpp

@observable

它与g ++ 8.0.1 ubuntu 18.04 hyper-v windows 10完美配合。我不这样做 我需要关心模板重复,因为我明确地使用了隐式实例化,在一个文件中,永远不会重复。所有功能&#39;在一个文件中的定义,我可以在构造函数中实例化它 班级&#34;考试&#34;在文件instantiate.h中。对于多个文件,我使用一个Instantiate,一个初始化和一个虚拟,可能有多个类的实现&#34; test&#34;。

答案 4 :(得分:0)

使用extern模板语法可以解决问题,例如:

 extern template int max (int, int);
相关问题