9

如果我有一堂课:

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_1它是相同的my_type_2,在其他情况下是不同的。我如何确保在所有情况下都可以编译上述内容?有没有办法忽略重复的实例化?

4

5 回答 5

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. 我也不确定上述 each 的使用template是否足以实例化它(即,它不会以某种方式被优化,并且符号将被导出)。

(递归深度取决于n类型的数量,而完成的总工作取决于n^2类型的数量:我怀疑对于任何合理数量的类型来说,它足够浅且足够快。由于缺乏弱点,更复杂的唯一类型移除很困难订购裸体类型......)

于 2013-06-18T18:57:46.437 回答
3

不要专门针对 typedef,而是专门针对相关的底层类型(例如 int)。这样,您可以根据需要多次/多次键入def,并且您仍然始终可以获得所需的专业化。

于 2013-06-18T17:40:51.153 回答
2

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

于 2013-06-18T17:31:00.620 回答
0

Yakk 救了我的命。实际上,我有很多非类型模板函数,它们在编译时计算的参数取决于一些“#define”。我不会提前知道它们的值,我想明确地实例化它们。但是当它们发生冲突时,编译器会因错误“重复...”而停止。所以我按照 Yakk 的想法做了一个非常简单的版本。我把它贴在这里给可能感兴趣的人。

文件 1:实例化.h

#ifndef INC_INSTANTIATE_H
#define INC_INSTANTIATE_H

#include <iostream>
#include <utility>
#include <type_traits>

using namespace std;

template<unsigned short base> void func();

template<unsigned short base>
struct test {
    test() {
        cout << "Class " << base << " instantiated.\n";
        func<base>();
    }
    void instantiate_me(){};
};

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

template<typename Types>
struct Instantiate {};

template<typename T0, typename... Ts>
struct Instantiate<instances<T0, Ts...>> : Instantiate<instances<Ts...>>
{
    T0 unused;
};

#endif

文件 2:实例化.cpp

#include <iostream>
#include "instantiate.h"

using namespace std;

static Instantiate<instances<test<1>, test<2>, test<3>, test<4>>> unused;

template<unsigned short base>
void func() {
    cout << "Function " << base << " instantiated.\n";
}

static int initialize() {
    unused.unused.instantiate_me();
    return 0;
}

static int dummy = initialize();

文件 3:main.cpp

#include <iostream>
#include "instantiate.h"
using namespace std;

int main() {
    cout << "Good day commander!\n";
}

它与 g++ 8.0.1 ubuntu 18.04 hyper-v windows 10 完美配合。在这里我不需要关心模板重复,因为我明确使用隐式实例化,在一个文件中永远不会有重复。将所有函数的定义放在一个文件中,我可以在文件 instantiate.h 中的类“test”的构造函数中实例化它。对于多个文件,我使用一个 Instantiate、一个 initialize 和一个 dummy,每个文件可能有多个“test”类的实现。

于 2018-06-10T15:53:36.440 回答
0

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

 extern template int max (int, int);
于 2019-09-15T15:02:03.790 回答