类模板的成员函数的显式实例化声明是否导致类模板的实例化? [英] Does an explicit instantiation declaration of a member function of a class template cause instantiation of the class template?

查看:290
本文介绍了类模板的成员函数的显式实例化声明是否导致类模板的实例化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

[dcl.spec.auto]/14 指出[重点我的]:

显式实例化声明不会导致实例化使用占位符类型声明的实体,但也不会阻止该实体根据需要实例化以确定其类型. [示例:

An explicit instantiation declaration does not cause the instantiation of an entity declared using a placeholder type, but it also does not prevent that entity from being instantiated as needed to determine its type. [ Example:

template <typename T> auto f(T t) { return t; }
extern template auto f(int);    // does not instantiate f<int>
int (*p)(int) = f;              // instantiates f<int> to determine its return type, but an explicit
                                // instantiation definition is still required somewhere in the program

最终示例]

[temp.explicit]/11 状态[强调我的]:

一个实体,它是显式实例化声明的主题,并且也以某种方式使用,否则会导致隐式实例化在翻译单元中,应该是程序中某个地方的显式实例化定义的主题; 否则,程序格式不正确,不需要进行诊断.

An entity that is the subject of an explicit instantiation declaration and that is also used in a way that would otherwise cause an implicit instantiation in the translation unit shall be the subject of an explicit instantiation definition somewhere in the program; otherwise the program is ill-formed, no diagnostic required.

现在,考虑以下程序:

template <class T>
struct Foo {
    static const auto& foo() { static T t; return t; }
};

// explicit instantiation declarations
extern template const auto& Foo<void>::foo();
extern template const auto& Foo<int>::foo();

int main() {}

这是格式正确的; [temp.explicit]/11 不适用根据

This is well-formed; [temp.explicit]/11 does not apply as neither member function of class template specialization entities Foo<void>::foo() nor Foo<int>::foo() are used in a way that would otherwise cause an implicit instantiation, as per [dcl.spec.auto]/14(1).

现在,考虑是否在类模板Foo中的朋友声明中定义了朋友函数:

Now, consider if we defined a friend function at its friend declaration in the class template Foo:

template <class T>
struct Foo {
    static const auto& foo() { static T t; return t; }
    friend void bar() { }
};
void bar();

如果在同一翻译单元中实例化了Foo的多个专业化,则 [basic.def.odr]/1 将被违反:

If any more than one specialization of Foo is instantiated in the same translation unit, [basic.def.odr]/1 will be violated:

任何变量,函数,类类型,枚举类型或模板的翻译单元均不得包含多个定义.

No translation unit shall contain more than one definition of any variable, function, class type, enumeration type, or template.

对于实例化的每个专业化,将

作为朋友bar()重新定义(2).

as the friend bar() would be re-defined(2) for each specialization that is instantiated.

根据上述参数,(类模板的)两个成员函数专门化的显式实例化声明不应导致关联的类模板的任何实例化(按照

According to the argument above, the explicit instantiation declarations of the two member function (of class template) specializations should not lead to any instantiation of the associated class template (as per [dcl.spec.auto]/14), meaning the following program should also arguably be well-formed:

template <class T>
struct Foo {
    static const auto& foo() { static T t; return t; }
    friend void bar() { }
};
void bar();

extern template const auto& Foo<void>::foo();
extern template const auto& Foo<int>::foo();

int main() {}

但是,Clang(10.0.0)和GCC(10.1.0)都拒绝程序(C ++ 14,C ++ 17,C ++ 2a),并显示"void bar()的重新定义"错误:

However, both Clang (10.0.0) and GCC (10.1.0) rejects the program (C++14, C++17, C++2a) with a "redefinition of void bar()" error:

C语

错误:bar

注意:在实例化模板类Foo<int>时,此处要求: extern template const auto& Foo<int>::foo();

note: in instantiation of template class Foo<int> requested here: extern template const auto& Foo<int>::foo();

海湾合作委员会

struct Foo<int>的实例中:

错误:重新定义void bar()

但是我从来没有要求(或以某种方式使用这些专门知识,以使)实例化Foo<int>Foo<void>专门知识.

But I never requested (or, afaict, used these specializations in a way such that) the Foo<int> or Foo<void> specializations (are) to be instantiated.

问题所在:

  • 上面的程序(和朋友一起)格式是否正确,还是编译器正确地实例化了类模板的专业化知识,并随后拒绝了该程序?

(1)请注意,即使未使用占位符类型声明foo(),也存在相同的问题(和编译器行为),但我们将无法依靠 [dcl.spec.auto]/14 ,但我们可能会不需要.

(1) Note the the same question (and compiler behaviour) applies even if foo() is not declared using a placeholder type, but then we would not be able to fall back on the explicitness of [dcl.spec.auto]/14, but we may not need to.

(2)由于在其好友声明中定义的好友是内联的,因此我们实际上可以在不同的翻译单元中实例化不同的专业知识,并且仍然会尊重ODR,但这在本讨论中无关紧要.

推荐答案

必须实例化类模板的论据是声明 matching 可能需要了解有关类的知识,而这些东西显然需要实例化.考虑简化的例子

The argument that the class template must be instantiated is that declaration matching may need to know things about the class that plainly require instantiation. Consider the simplified example

template<class T>
struct A {void f(T) {}};

extern template void A<int>::f(int);

要知道成员函数是否存在,我们必须实例化类模板中的声明,并且通常不能在不实例化整个类的情况下做到这一点:参数类型可以依赖于任何其他 >在类模板中进行声明,我们可能需要考虑多个重载,甚至进行模板参数推导来确定是哪个f.有人可以说,只有在其中一种情况确实存在时才应进行实例化,这会误入

To know whether the member function exists, we must instantiate the declaration in the class template, and we can’t do that in general without instantiating the whole class: the parameter type could depend on any other declarations in the class template, and we might need to consider multiple overloads or even do template argument deduction to decide which f is meant. One can argue that instantiation should happen only if one of these situations actually pertains, which strays into CWG2 territory (where instantiation is obviously impossible), but the idea is that instantiation is necessary in principle to decide about such questions because we simply don’t try examining the template itself first.

这篇关于类模板的成员函数的显式实例化声明是否导致类模板的实例化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆