Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why did C++03 require template parameters to have external linkage?

Tags:

c++

templates

Background

In C++03, symbols used as template arguments must have external linkage; this restriction was removed in C++11, as explored in this previous question:

In C++03, template arguments could not have internal linkage:

[C++03: 14.6.4.2/1]: For a function call that depends on a template parameter, if the function name is an unqualified-id but not a template-id, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2) except that:

  • For the part of the lookup using unqualified name lookup (3.4.1), only function declarations with external linkage from the template definition context are found.
  • For the part of the lookup using associated namespaces (3.4.2), only function declarations with external linkage found in either the template definition context or the template instantiation context are found.

[..]

This was changed (issue #561: "Internal linkage functions in dependent name lookup") in C++11:

[C++11: C.2.6]: 14.6.4.2
Change: Allow dependent calls of functions with internal linkage
Rationale: Overly constrained, simplify overload resolution rules.

resulting in:

[C++11: 14.6.4.2/1]: For a function call that depends on a template parameter, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2, 3.4.3) except that:

  • For the part of the lookup using unqualified name lookup (3.4.1) or qualified name lookup (3.4.3), only function declarations from the template definition context are found.
  • For the part of the lookup using associated namespaces (3.4.2), only function declarations found in either the template definition context or the template instantiation context are found.

[..]

(Spot the missing "with external linkage" qualification.)

Issue #561 ("Internal linkage functions in dependent name lookup"), the proposal that led to the restriction being removed in C++11, asks:

Furthermore, is it really necessary to exclude internal linkage functions from the lookup? Doesn't the ODR give implementations sufficient latitude to handle this case without another wrinkle on name lookup?

With the later answer:

The consensus of the group was that [..] internal-linkage functions should be found by the lookup (although they may result in errors if selected by overload resolution).


Question

What was the original practical rationale for the restriction?

It seems like there must have been one, since the original standard wording went out of its way to limit lookup to symbols with external linkage.

Is it just that "[internal-linkage functions] may result in errors if selected by overload resolution", and that through the 2000s opinion shifted over how important this was? Or did something else change, perhaps as an indirect consequence of new wording elsewhere for a different C++11 feature?

like image 416
Lightness Races in Orbit Avatar asked Jan 30 '13 05:01

Lightness Races in Orbit


People also ask

Why do we use template template parameter?

Why we use :: template-template parameter? Explanation: It is used to adapt a policy into binary ones.

Which is a correct example of template parameters?

For example, given a specialization Stack<int>, “int” is a template argument. Instantiation: This is when the compiler generates a regular class, method, or function by substituting each of the template's parameters with a concrete type.

What are non type parameters for templates?

A template non-type parameter is a template parameter where the type of the parameter is predefined and is substituted for a constexpr value passed in as an argument. A non-type parameter can be any of the following types: An integral type. An enumeration type.


2 Answers

I would suspect it's related to the infamous export template feature of C++98. Think about it. Once you allow the possibility of template definitions appearing in separate translation units, but still not truly compilable until the template arguments are specified (i.e., the template is instantiated), you get into this twilight zone where the TU with the definition of the template and the TU with the instantiation have to obey linker-visibility rules (i.e., separation model) while sharing their contexts in terms of overload resolution. The solution to that problem is to allow only functions with external linkage in the dependent name lookups.

Here's an example. One of the lesser known "feature" of exported templates is that you could have, in the template's TU, some functions or classes with internal linkage (i.e., marked static or in an un-named namespace). What if the TU with the instantiation has a internal-linkage function too, one that would be ambiguous with or possibly superceded by the one in the template's TU? That's a bit of a surreal problem, I know, it's the bizarro world of exported templates. The only way to avoid very surprising behavior is to rule out all internal-linkage functions from the lookups. Consider also that no-one had a clear idea of how to actually implement exported templates, and it would probably seem even more impossible to implement without this restriction.

And so, once exported templates are out, the restriction on dependent name lookups seems clearly useless and it was taken out without much debate. At least, that makes perfect sense to me, but, of course, it's speculation.

Here's a concrete example:

// in exptemp.h
export template <typename T> bool is_valid(T value);

// in exptemp.cpp
namespace {
  bool is_space(char c) {
    return (c == ' ') || (c == '\t');
  };
};

template <typename T>
bool is_valid(T value) {
  return is_space(value);
};

// in test.cpp
#include "exptemp.h"

namespace {
  bool is_space(char c) {
    return (c == ' ') || (c == '\t') || (c == '\n');
  };
};

int main() {
  char c = '\n';
  return is_valid(c);   // will this return 0 or 1 ?!?!?
};
like image 86
Mikael Persson Avatar answered Oct 13 '22 22:10

Mikael Persson


As far as I know, it's purely historical -- it seems to have originally been banned because cfront's name mangling wasn't sufficient to handle it correctly.

At one point, Anthony Williams wrote a paper proposing that it would be allowed, and telling how to do it -- but AFAIK, that paper has never been accepted nor its requirements edited into the standard. I suspect that's as much a matter of timing as anything else though. It was proposed in 2001, so what they were working on at the time (C++ 2003) wasn't intended to add much new material, and by the time they started working in earnest on C++11, it seems to have been mostly forgotten.

like image 34
Jerry Coffin Avatar answered Oct 13 '22 23:10

Jerry Coffin