【问题标题】:Prevent compilation of unused template specialization in c++防止在 C++ 中编译未使用的模板特化
【发布时间】:2018-05-19 04:11:22
【问题描述】:

让我们考虑一个结构 Foo,它由一个名为 TYPE 的枚举模板化:

enum TYPE
{
    TYPE_A,
    TYPE_B
};

template<TYPE T>
struct Foo;

Foo 没有定义,但只特化了两次。一种特化将int* 添加到类,而另一种则添加指向MayBeNotDefined 类型对象的指针:

template<>
struct Foo<TYPE_A>
{
    int* A;
};

template<>
struct Foo<TYPE_B>
{
    MayBeNotDefined* B;
};

我的一些项目中没有定义MayBeNotDefined类型,所以只使用了Foo&lt;TYPE_A&gt;

int main()
{
    Foo<TYPE_A> a;
    a.A = new int;
    //...
}

在其他项目中,MayBeNotDefined 实际上是在 Foo 的声明之前定义的(类似于 using MayBeNotDefined = int;)并且同时使用了 Foo&lt;TYPE_A&gt;Foo&lt;TYPE_B&gt;

int main()
{
    Foo<TYPE_A> a;
    Foo<TYPE_B> b;
    //...
}

问题是,在第一种情况下,编译器会为两种特化生成代码,即使我只使用Foo&lt;TYPE_A&gt;...因此,由于MayBeNotDefined 未知,所以会发生错误。

所以我有两个问题:

  • 为什么编译器需要为每个特化生成代码? 我天真地以为如果编译器遇到Foo&lt;TYPE_A&gt;类型的变量,那么它只会生成第一个特化的代码。如果没有解析Foo&lt;TYPE_B&gt;,为什么还需要生成关联代码?

  • 如何防止编译器为未使用的特化编译代码? 有没有简单的解决方法,最好不使用预处理器宏?似乎可以“删除”已编译但未使用的代码 (cf G++ generates code for unused template specializations?)。我想要的是代码甚至根本没有编译,这样未定义的类型MayBeNotDefined就不是问题了。

谢谢!

【问题讨论】:

  • 模板仍然需要编译,即使它们没有被使用,就像任何其他功能一样。 if constexpr 在这里为您提供了更多的灵活性,但我不认为它比 #ifdef 更好。
  • 您需要提供minimal reproducible example。编译器认为必须生成对模板实例的引用可能是有原因的,而您忽略了这一点。其中很多是特定于编译器的,但如果没有minimal reproducible example,所有可以说的都是纯粹的猜测。

标签: c++ templates compilation conditional-compilation specialization


【解决方案1】:

为什么编译器需要为每个特化生成代码?

编译器不需要为未使用的模板特化生成代码,但它必须根据与泛型类相同的规则确保其定义是正确的。

如何防止编译器为未使用的特化编译代码?

你不能。未使用的特化必须编译,但如果编译,(体面的)编译器将不会为它生成二进制代码。

但是,如果您告诉我们您的确切期望,我们可能会为您提供替代方案。例如:

enum TYPE
{
    TYPE_A,
    TYPE_B
};


template<TYPE T>
struct MayBeNotDefined;


// FOR PROJECT WITH MayBeNotDefined ONLY ---
template<>
struct MayBeNotDefined<TYPE_B> { typedef char type; };
// FOR PROJECT WITH MayBeNotDefined ONLY ---

template<TYPE T>
struct Foo
{
    typename MayBeNotDefined<T>::type* B;
};

template<>
struct Foo<TYPE_A>
{
    int* A;
};


int main()
{
    Foo<TYPE_A> a;
    a.A = new int;

    // FOR PROJECT WITH MayBeNotDefined ONLY ---
    Foo<TYPE_B> b;
    b.B = new char;
    // FOR PROJECT WITH MayBeNotDefined ONLY ---
}

(即使您删除了两个指定的块也可以使用)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-06
    • 2012-05-28
    • 1970-01-01
    • 1970-01-01
    • 2016-06-05
    相关资源
    最近更新 更多