Why can't templates use local types?

In C ++, it is normal to have a function that accepts a function of a local type:

int main() { struct S { static void M(const S& s) { } }; S s; S::M(s); } 

but not OK to have a template:

 template<typename T> void Foo(const T& t) { } int main() { struct S { } s; Foo(s); // Line 5: error: no matching function for call to 'Foo(main()::S&)' } 

14.3.1 clause 2 in the C ++ standard.

A type without a binding [...] should not be used as a template argument for a template type parameter

Why does C ++ forbid this?


The best explanation I've heard so far is that inner types have no connection, and that this could mean that a function that accepts them as arg should not have any connection. But there is no reason why I see that the template instance must have a connection.


ps Please do not just say that " this is not permitted because the standard does not say so"

+6
c ++ language-design templates
source share
2 answers

I assume that this is due to the fact that the template should be effectively created as part of the function, since such types are visible there. However, at the same time, it is assumed that the template instances act as if they were in the area in which the template is defined. I am sure that it is possible to somehow deal with this, but if I am right, the standardization body decided not to place this burden on the authors of the compiler.

A similar solution was the reason that vector<vector<int>> is not valid syntax for the standard; discovering that building requires some interaction between the compiler lexer and the parser phases. However, this change is because people in the C ++ 0x standard have found that all compilers will still detect it in order to emit normal error messages.

I suspect that if it were demonstrated that allowing this construct is trivial to implement, and that it does not introduce any ambiguities in the rules for defining a language, you might someday see that the standard has changed too.

+3
source share

I believe the difficulty that was envisioned was that the two instances of Foo<T> actually meant completely different things, because T not the same for both. A few early template implementations (including cfront) used a template repository, so the compiler could automatically create a template over the required type when / if it was discovered that an instance of this type was not in the repository yet.

To make this work with local types, the repository would not just save the type by which the template was created, but instead, it would have to do something like create a complete "path" to the type for instantiation. Although perhaps this is possible, I think it was perceived as most of the extra work for a small (if any) real benefit.

Since then, the rules have changed so much that the compiler already needs to do something roughly equivalent, find (and coalesce) instances of the same type in different places (including through TU) so that two instances of foo<int> (for example) Do not violate ODR. Based on this implementation, the restriction was relaxed in (current project) C ++ 0x (you still cannot create an instance of the template class by the local type, but you can use the local type as a parameter for the template function).

+7
source share

All Articles