gpt4 book ai didi

c++ - 类模板的成员函数的显式实例化声明是否会导致类模板的实例化?

转载 作者:行者123 更新时间:2023-12-03 07:21:41 24 4
gpt4 key购买 nike

[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

 — end example ]


[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不适用于类模板特化实体的成员函数 Foo<void>::foo()也不是 Foo<int>::foo()根据 [dcl.spec.auto]/14,以否则会导致隐式实例化的方式使用(1)。
现在,考虑我们是否在类模板 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将被违反:

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


作为 friend bar()将为每个实例化的特化重新定义(2)。
根据上面的论点,两个成员函数(类模板的)特化的显式实例化声明不应导致关联类模板的任何实例化(根据 [dcl.spec.auto]/14),这意味着以下程序也应该可以说是好的-形成:
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()”错误:

Clang

error: redefinition of bar

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

GCC

In instantiation of struct Foo<int>:

error: redefinition of void bar()


但是我从来没有要求(或者,afaict,以某种方式使用这些特化) Foo<int>Foo<void>特化(是)被实例化。
因此对于这个问题:
  • 上面的程序(和 friend 一起)是否格式正确,或者编译器是否正确实例化类模板特化并随后拒绝该程序?

  • (1) 请注意同样的问题(和编译器行为)适用,即使 foo()没有使用占位符类型声明,但是我们将无法依赖 [dcl.spec.auto]/14 的明确性,但我们可能不需要。
    (2) 由于在友元声明中定义的友元是内联的,我们实际上可以在不同的翻译单元中实例化不同的特化,并且仍然尊重 ODR,但这与本次讨论无关。

    最佳答案

    必须实例化类模板的参数是声明 匹配 可能需要知道关于类的事情,这些事情显然需要实例化。考虑简化的例子

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

    extern template void A<int>::f(int);
    要知道成员函数是否存在,我们必须实例化类模板中的声明,一般不实例化整个类是无法做到的:参数类型可以依赖于任何 其他 类模板中的声明,我们可能需要考虑多个重载甚至做模板参数推导来决定哪个 f是指。有人可以争辩说,只有当其中一种情况确实存在时才应该发生实例化,这偏离了 CWG2。领域(显然不可能实例化),但想法是实例化原则上对 是必要的决定关于此类问题,因为我们根本不尝试首先检查模板本身。

    关于c++ - 类模板的成员函数的显式实例化声明是否会导致类模板的实例化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64917707/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com