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

465 views Asked by At

I am asking myself why the following code works and what the specifier extern does when instantiating 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;
}

Why does the above code compile in the first place and why doesn't it compile anymore if the extern specifier is left out? What does the extern specifier do in this example?

4

There are 4 answers

0
Barry On BEST ANSWER

This is one of the parts of the standard that changed from C++03 to C++11.

In C++03, [temp.arg.nontype] reads:

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
  • [...]

In C++11, that got updated as a result of issue 1155, though GCC still has a bug with regards to this behavior:

  • 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

In C++14, that got simplified even further and doesn't even mention linkage.

As to your specific question, the extern specifier adds external linkage to baz_instance. Without it, baz_instance has internal linkage. In C++03, you needed external linkage to have a non-type template parameter of reference type. In C++11, you don't anymore - so extern is no longer necessary and it compiles fine without it.

1
Lawrence Aiello On

The extern keyword indicates that the variable was defined in another compilation unit (source file).

So in your case, baz should be defined in a different source file and extern is a way of saying this is a variable not defined in this source file, but in a different one, and you will find it during compilation.

The extern keyword means "declare without defining". In other words, it is a way to explicitly declare a variable, or to force a declaration without a definition.

0
Captain Giraffe On

From 14.3.2.1 the standard states:

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;

From https://stackoverflow.com/a/643927/451600 by mweerden

0
Nir Friedman On

The extern keyword means that it will have external linkage, in other words the symbol will be exported when the translation unit will be compiled. Because your type is const, it by default has internal linkage (as though it has been declared static). Templates cannot depend on types that only have internal linkage.

I would love to know the reason why, but it seems like it's lost to the sands of time: Why did C++03 require template parameters to have external linkage?.