Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't templates take function local types?

In C++ it's OK to have a funcction that takes a function local type:

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

but not OK to have a template that does:

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 paragraph 2 in the c++ standard.

A type with no linkage [...] shall not be used as a template-argument for a template type-parameter

Why does C++ disallow that?


The best explanation I've heard so far it that inner types have no linkage and that this could imply that a function that takes them as an arg must have no linkage. But there is no reason I can see that a template instantiation must have linkage.


p.s. Please don't just say "thats not allowed because the standard says it's not"

like image 644
BCS Avatar asked Aug 12 '10 17:08

BCS


People also ask

Can templates be used for functions?

Templates are powerful features of C++ which allows us to write generic programs. We can create a single function to work with different data types by using a template.

Can we pass non-type parameters to templates?

Template non-type arguments in C++It is also possible to use non-type arguments (basic/derived data types) i.e., in addition to the type argument T, it can also use other arguments such as strings, function names, constant expressions, and built-in data types.

Which Cannot be declared as a template?

Which of the following cannot be declared as template ? Correct Answer : OPTION D, Macros. Macros are implemented in a preprocessor and cannot be implemented as a template. Functions and classes can be declared as templates.

What are the differences between function template and template function?

"A function template is a template that is used to generate functions. A template function is a function that is produced by a template. For example, swap(T&, T&) is a function tem-plate, but the call swap(m, n) generates the actual template function that is invoked by the call."


2 Answers

I believe the difficulty that was foreseen was with two instantiations of Foo<T> actually meaning entirely different things, because T wasn't the same for both. Quite a few early implementations of templates (including cfront's) used a repository of template instantiations, so the compiler could automatically instantiate a template over a required type when/if it was found that an instantiation over that type wasn't already in the repository.

To make that work with local types, the repository wouldn't just be able to store the type over which the template was instantiated, but instead it would have to do something like creating a complete "path" to the type for the instantiation. While that's probably possible, I think it was seen as a lot of extra work for little (if any) real benefit.

Since then, the rules have changed enough that the compiler is already required to do something that's just about equivalent, finding (and coalescing) instantiations over the same type at different places (including across TUs) so that two instantiations of foo<int> (for example) don't violate the ODR. Based on that realization, the restriction has been loosened in (the current draft of) C++0x (you still can't instantiate a template class over a local type, but you can use a local type as parameter to a template function).

like image 58
Jerry Coffin Avatar answered Sep 27 '22 16:09

Jerry Coffin


I'm guessing it is because it would require the template to be effectively instantiated within the scope of the function, since that is where such types are visible. However, at the same time, template instantiations are supposed to act as if they are in the scope in which the template is defined. I'm sure this it's possible to deal with that somehow, but if I'm right the standards body decided not to put that burden on compiler writers.

A similar decision was the reason vector<vector<int>> is invalid syntax per the standard; detecting that construction requires some interaction between compiler lexer and parser phases. However, that's changing, because the C++0x standards folk found that all the compilers are detecting it anyway to emit sane error messages.

I suspect that if it were to be demonstrated that allowing this construction was trivial to implement, and that it didn't introduce any ambiguities in the language scoping rules, you might someday see the standard changed here too.

like image 26
Walter Mundt Avatar answered Sep 27 '22 17:09

Walter Mundt