使用 extern const 将结构传递给模板。什么是外部?

Passing a struct to a template with extern const. What is the extern for?

我在问自己为什么下面的代码有效以及说明符 extern 在实例化 baz_instance 时做了什么:

struct baz {
    int value;
};

extern const baz baz_instance = {3};

template<baz const& b>
int foo(){
    return b.value;
}

int main(){
    foo<baz_instance>();
    return 1;
}

为什么上面的代码首先编译,如果 extern 说明符被省略,为什么它不再编译? extern 说明符在此示例中的作用是什么?

extern关键字表示该变量是在另一个编译单元(源文件)中定义的。

所以在你的情况下,baz 应该 在不同的源文件中定义,extern 是一种表示这是一个未在此源文件中定义的变量的方式, 但在不同的地方,你会在编译时找到它。

关键字extern表示"declare without defining"。换句话说,它是一种显式声明变量的方法,或者强制声明没有定义。

从 14.3.2.1 开始,标准规定:

A template-argument for a non-type, non-template template-parameter shall be one of:

  • the address of an object or function with external linkage, including function templates and function template-ids but excluding non-static class members, expressed as & id-expression where the & is optional if the name refers to a function or array, or if the corresponding template-parameter is a reference;

来自 作者:mweerden

extern关键字意味着它会有外部链接,换句话说,编译单元时会导出符号。因为您的类型是 const,所以默认情况下它具有内部链接(就好像它已被声明为 static)。模板不能依赖于只有内部链接的类型。

我很想知道原因,但它似乎已经消失在时间的流逝中:Why did C++03 require template parameters to have external linkage?

这是标准中从 C++03 更改为 C++11 的部分之一。

在 C++03 中,[temp.arg.nontype] 表示:

A template-argument for a non-type, non-template template-parameter shall be one of:

  • [...]
  • [...]
  • the address of an object or function with external linkage, including function templates and function template-ids but excluding non-static class members, expressed as & id-expression where the & is optional if the name refers to a function or array, or if the corresponding template-parameter is a reference; or
  • [...]

在 C++11 中,issue 1155, though GCC still has a bug 更新了关于此行为的结果:

  • a constant expression (5.19) that designates the address of a complete object with static storage duration and external or internal linkage or a function with external or internal linkage, including function templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as & id-expression, where the id-expression is the name of an object or function, except that the & may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference; or

在 C++14 中,这得到了进一步简化,甚至没有提到链接。

关于您的具体问题,extern 说明符将外部链接添加到 baz_instance。没有它,baz_instance 有内部链接。在 C++03 中,您需要外部链接才能拥有引用类型的非类型模板参数。在 C++11 中,你不再需要 - 所以 extern 不再是必需的,没有它它编译得很好。