Why can't template functions be passed as a template template parameter? - c++

When i am trying to pass a function as a template template type parameter to a class, error encountered. Why language core developers won't enable this ability? Functor class templates could be passed, but function templates can't.
For example, compiling this code in "g++ (Ubuntu 8.3.0-6ubuntu1) 8.3.0":
#include <iostream>
using namespace std;
template <template <typename> typename Functor>
class UseFunc
{
public:
void use()
{
Functor<int>(3);
Functor<char>('s');
}
};
template <typename T>
void func(T s)
{
cout << s << endl;
}
int main()
{
UseFunc<func> u {};
u.use();
}
tells:
kek.cpp: In function ‘int main()’:
kek.cpp:24:14: error: type/value mismatch at argument 1 in template parameter list for ‘template<template<class> class Functor> class UseFunc’
UseFunc<func> u {};
^
kek.cpp:24:14: note: expected a class template, got ‘func’
kek.cpp:25:4: error: request for member ‘use’ in ‘u’, which is of non-class type ‘int’
u.use();
^~~
I expected it to be implemented the same way as template template parameter passing is. At the end of the day it is just a request to compiler, so that functions of concrete types could be instantiated and used in a usual way.
Truly don't understand this limitation and it would be great if someone could tell me what is the difficulty of implementing this.

I don't know for sure the answer to the question of why C++ does not provide function template template parameters, but I imagine it has something to do with:
Any nontrivial change to templates will require complicated analysis to determine what changes need to be made to the standard text
This feature would be rarely used; after all, class template template parameters are mostly used in partial specializations, i.e., to dispatch on types that are themselves template specializations, and it's rare to want to do that with functions
It wouldn't make sense to support function template template parameters without also supporting a type of template parameter that would accept any non-template function (we can do this in C++17 with auto but this is obviously way too late for C++98 to have function template template parameters)
You can work around the lack of function template template parameters using class templates anyway (sort of like what we do with partial specializations).
Function overloading complicates things. In the presence of overloading, there's no way to unambiguously name a particular function template. Should one be provided? Or, do we take the point of view that an overload set is meant to be passed as a whole to a function template template parameter? What if overload resolution then selects a non-template overload? How do we even answer these design questions without having a compelling use case?
If you believe that you know how to address all these concerns, and in particular can provide a compelling argument for why we need this feature in the language despite the fact that it would be complicated and we can work around its absence using class template template parameters, feel free to write up a proposal for the standard.

Related

Can C++11 deduce class type and member type from pointer-to-member template parameter

I'd like to make a traits class to deduce the class and member types
from the pointer to a class member -- a single template parameter.
e.g.
given
struct Example { int val; };
, I want a class
pointer_member<&Example::val>
with type definitions class_type=Example, member_type=int and the pointer-to-member itself.
I know c++17 can do this with template <auto>, but I'm stuck with c++11.
I know I could explicitly specify the class and member typenames preceding the pointer-to-member parameter. I hate redundancy. The compiler should know everything from &Example::val.
I know I could create a template function having template parameters <typename class_type,typename member_type> deduced by calling with a function argument member_type class_type::*ptr_to_mem. I'd even be willing to use the decltype() of such a call. Unfortunately, I need to access the specific member ptr_to_mem as a template parameter, not (just) as a passed argument. I cannot see how.
The Motivation and Scope of P0127r1 suggest this is not possible with C++11.
ManuelAtWorks' answer appears the best option for C++11.
In c++17, template <auto value> which allows pointer_member<&Example::val> usage.
For previous version, there are workaround, such as template <typename T, T value> with usage changed to pointer_member<decltype(&Example::val), &Example::val>
MACRO can simplify usage a little:
#define AUTO(value) decltype(value), value
and then
pointer_member<AUTO(&Example::val)>

Class template argument deduction for template type which is itself an argument for a template

Is class template argument deduction supported for template types with default arguments which are used within another template type declaration? The following code does not compile with both Clang/GCC trunk, it fails on the line defining y:
#include <optional>
template <class T = char>
struct C {};
int main() {
C x;
std::optional<C> y;
}
(https://godbolt.org/z/SgxY90)
Modifying the code to read std::optional<C<>> y fixes the issue, but I am a bit surprised this is needed. Is this a compiler issue, or a known language limitation?
The compiler has to verify that what is passed to the template matches the anticipated template parameter. Now consider I were to write this with your example, where you don't see foo:
foo<C> f;
Is it a instance of CTAD, or am I passing the template itself? Since one can already pass templates as arguments to other templates.
template< template<typename> class T > struct foo {};
Allowing for CTAD in that context would make the use of C context dependent. In contrast, a template name has no other use when declaring a variable. There is no ambiguity when writing...
C c;
... that can mean something other than CTAD, so it's allowed here. But context matters when the template name is used as a template argument. C++ has a lot of context dependent constructs already, so adding more is usually a bad idea.

Are all valid templates instantiated?

When I have multiple templates that could be instantiated, what happens?
template <typename T> void foo(T*);
template <typename T> void foo(T**);
template void foo(int**);
template <typename T> void foo(T*) { printf("called foo(T*)\n"); }
template <typename T> void foo(T**){ printf("called foo(T**)\n"); }
When we need to instantiate a foo(int**), either of the instantiations would work, one with T=int* and the other with T=int**. In practice, the object file only contains one, the T** one. On the other hand, if I put a static_assert(false) into the unused one, the compilation fails. Does that mean that it is instantiated?
It turns out that the T** is the one that I want to use in this case. But even if both were instantiated, overload resolution would pick the T** one, so this works for me either way.
Now in my actual code, I request two instantiations:
template void foo(int*);
template void foo(int**);
That instantiates foo<int>(int**) and foo<int>(int*), so I get both templates. The latter is forced, since template <typename T> foo(T**) doesn't match. But I don't understand the rules to know why I don't get foo<int*>(int**) for the former. Or both foo<int*>(int**) as well as foo<int>(int**).
And yes, I realize I could do template void foo<int*>(int**) if I needed to force it.
All this makes me realize I don't really understand what happens when the compiler sees a call that requires a template instantiation. Does it scan through templates until it finds one that works, then stop? Or does it instantiate all valid options (and then something discards the unneeded ones from the object file)?
Template argument deduction is performed to figure out what function template specialization is named by template void foo(int**);; it selects the T** one after considering partial ordering. See [temp.deduct.decl] and sections linked therein. That's roughly the same process used to pick the function template to call during overload resolution (with some minor differences).
There's no mechanism for instantiating everything that matches. If the compiler can't select a unique function template specialization, the program is simply ill-formed.
On the other hand, if I put a static_assert(false) into the unused one, the compilation fails. Does that mean that it is instantiated?
That's just [temp.res]/8 at work, as usual. Code that is ill-formed in a way that doesn't depend on a template parameter may be diagnosed immediately without instantiation.
if I put a static_assert(false) into the unused one, the compilation fails. Does that mean that it is instantiated?
No. The compiler does some basic checks on a template definition. Everything in the definition must be valid C++, but certain things which depend on a template parameter cannot be checked until an actual instantiation, when the template arguments are known. Since static_assert(false); does not depend on any template parameters, it always causes an error, and a compiler is allowed to note the error even when the template is never instantiated.
If you really want a template that should never be instantiated, the usual way is to use =delete for a function template, or leave a class template undefined.
But I don't understand the rules to know why I don't get foo<int*>(int**) for the former.
In most contexts that name a specialization of a function template, there's a rule that any template which is "more specialized" than all other viable overloads is the one that gets used. The exact definition of "more specialized" is a bit tricky, but the basic idea is that if any argument list that could be taken by a function template "A" could also be taken by a function template "B" but not vice versa, then "A" is more specialized. In your example
template <typename T> void foo(T*); // #1
template <typename T> void foo(T**); // #2
if an argument arg has type U** for any type U so that template argument deduction for template #2 for foo(arg) can succeed with T=U, we can see that template argument deduction for template #1 for foo(arg) can also succeed with T=U*. On the other hand, it's obviously possible that another argument arg2 can mean that template argument for foo(arg2) can succeed for template #1 but fail for template #2, for example if arg2 has type int*. So function template #2 is more specialized than function template #1. This means an expression like foo(arg), whenever type deduction for both succeeds (and there are no other viable overloads involved), means a use of template #2.
The same "more specialized" rule applies in your explicit instantiation
template void foo(int**);
Much like with a function call expression, the compiler will use template argument deduction to see whether the declaration you gave matches each function template. In this case both succeed, but since template #2 is more specialized, the declaration is interpreted as a specialization of #2 and not #1.
All this makes me realize I don't really understand what happens when the compiler sees a call that requires a template instantiation. Does it scan through templates until it finds one that works, then stop? Or does it instantiate all valid options (and then something discards the unneeded ones from the object file)?
The rough sequence for most uses of the name of an overloaded function template is:
Do name lookup to determine the list of function templates and functions to be considered.
For each function template in the list, attempt template argument deduction. If template argument deduction fails, or if substituting any template argument into the function type fails, ignore that template from here on. If successful, this results in a template argument for each template parameter, and one specific function type for the specialization.
Do overload resolution in mostly the same way as for non-templates, on the set of non-template functions initially looked up combined with the set of function template specializations determined above. But if two candidate functions cannot be ordered to say one is a better overload than the other just based on the parameter types and implicit conversions involved, then a non-template function beats a function template specialization, and a specialization from a more specialized function template beats a specialization from a less specialized function template.
Note that during this process, the function types but not the definitions of the function template specializations are instantiated.

Can a single member of a class template be partially specialized?

I came across an interesting point that I wasn't able to explain or find an explanation for. Consider the following template definition (compiled with mingw g++ 4.6.2):
template <typename T, typename S>
class Foo
{
public:
void f(){}
void g(){}
};
Should we want to, we can fully specialize any single member function:
template <>
void Foo<char,int>::f() {}
But partial specialization fails with an "invalid use of incomplete type 'class Foo<...>'" error:
template <typename T, typename S>
void Foo<T,S*>::f()
{
}
template <typename T>
void Foo<T,int>::f()
{
}
And I can't figure out why. Is it a conscious design decision made to avoid some problem I can't foresee? Is it an oversight?
The notion of partial specialization only exists for class templates (described by §14.5.5) and member templates (i.e. members of a template class that are themselves template functions, described by §14.5.5.3/2). It does not exist for ordinary members of class templates, nor does it exist for function templates – simply because it is not described by the Standard.
Now, you might argue that by giving the definition of a partial specialization of a member function, such as
template <typename T>
void Foo<T,int>::f()
{ }
you implicitly define a partial specialization of the class template: Foo<T,int>. That, however, is explicitly ruled out by the Standard:
(§14.5.5/2) Each class template partial specialization is a distinct template and definitions shall be provided for the members of a template partial specialization (14.5.5.3).
(§14.5.5.3/1) [...] The members of the class template partial specialization are unrelated to the members of the primary template. Class template partial specialization members that are used in a way that requires a definition shall be defined; the definitions of members of the primary template are never used as definitions for members of a class template partial specialization. [...]
The latter implies that it is impossible to implicitly define a partial specialization by simply giving the definition of one of its members: The very existence of that member would not follow from the definition of the primary template, hence defining it is equivalent to defining a member function that wasn't declared, and that isn't allowed (even with non-template classes).
On the other hand, the notion of explicit specialization (or full specialization, as you call it) exists for member functions of class templates. It is explicitly described by the Standard:
(§14.7.3/1) An explicit specialization of any of the following:
[...]
— member function of a class template
[...]
can be declared by a declaration introduced by template<>; [...]
§14.7.3/14 describes the details:
(§14.7.3/14) A member or a member template of a class template may be explicitly specialized for a given implicit instantiation of the class template, even if the member or member template is defined in the class template definition. [...]
Hence, for explicit specializations of members, the instantiation of the rest of the class template works implicitly – it is derived from the primary template definition, or any partial specializations if defined.
I tried to find a succinct quote from the standard, but I don't think there is one. The fact is, there is no such thing as a partial specialization of a template function (or, for that matter, of a template alias). Only class templates can have partial specializations.
Let's forget about templates for a second. In C++, there is a big difference between class names and function names. There can only be one definition of a class within a given scope. (You can have various declarations, but they all refer to the One True Class.) So the name really identifies the class.
A function name, on the other hand, is a kind of group identity. You can define any number of functions within a scope with exactly the same name. When you use a function name to call a function, the compiler has to figure out which function you really meant by looking at the various possibilities and matching the signature of each of them with the supplied arguments. There's no relationship between the various functions which share a name; they're completely separate entities.
So, no big deal. You knew all this, right? But now let's go back to templates.
The name of a templated class is still unique. Although you can define partial specializations, you have to explicitly specialize the same templated class. This mechanism looks superficially like the function-name resolution algorithm referred to above, but there are significant differences -- one of them is that, unlike function prototypes, you cannot have two class templates in the same scope with different kinds of template parameters.
Templated functions, on the other hand, have no need to define unique names. Templating does not replace the normal function overload mechanism. So when the compiler is trying to figure out what a function name means, it has to consider all templated and non-templated declarations for that function name, resolve the templated ones to a set of template parameter assignments (if possible) and then once it has a list of possible function objects, select the best one with normal overload resolution.
That's quite a different algorithm from the templated class template parameter resolution. Instead of just matching a list of provided template arguments with a list of declared template parameters, which is how it resolves class templates, it has to take each templated function which might possibly match (has at least the right number of parameters, for example); deduce template parameters by unifying the supplied arguments with the template; and then add the resolve specialization to the overload set for a further round of overload resolution.
I suppose it would have been possible to have added partial specialization resolution into that process as well, but the interactions between partial specialization and function overloading strike me as likely to lead to pseudo-magical behaviour. In the event, it wasn't necessary and so there is no such mechanism. (You can fully specialize a function template. Full specialization means that there are no template arguments to deduce, so it's not a problem.)
So that's the scoop: you can't partially specialize a templated function, but there is nothing stopping you from providing any number of function templates with the same name. All of them will be considered in overload resolution, and the best one will win, as usual.
Usually, that's actually sufficient for your overloading needs. You should think about templated functions just the same way you think about normal functions: come up with a way to select the one you want based on the supplied arguments. If you feel you really need to supply template parameters in a function call, rather than having them be deduced, just make the function a (possibly static) member of a templated class, and supply the template arguments to the class.
Hope that helps...
I think that the difference is that when you do the first (valid) explicit specialization of f:
template <>
void Foo<char,int>::f() {}
You are doing an implicit instantiation of Foo<char,int>. But when you try the partial specialization with:
template <typename T>
void Foo<T,int>::f()
{
}
The compiler would need to instantiate implicitly Foo<T,int> before doing the specialization, but it cannot do that because of the T. And it fails.
You can check that is the case with the following code:
template <typename T, typename S>
class Foo
{
public:
void f(){}
void g(){}
};
template <>
void Foo<char,int>::f() //line 11
{}
template <>
class Foo<char,int> //line 15
{};
With g++ it gives the errors:
test.cpp:15:7: error: specialization of ‘Foo<char, int>’ after instantiation
test.cpp:15:7: error: redefinition of ‘class Foo<char, int>’
test.cpp:2:7: error: previous definition of ‘class Foo<char, int>’
With clang++ is a bit clearer:
test.cpp:15:7: error: explicit specialization of 'Foo<char, int>' after instantiation
class Foo<char,int>
^~~~~~~~~~~~~
test.cpp:11:6: note: implicit instantiation first required here
void Foo<char,int>::f()
^

Are template template template parameters an extension or part of the standard?

I was searching for something else related to template template parameters and happened upon this answer which claims that template template template parameters are not allowed by the standard.
However, the following code compiles in the latest clang (3.2) and the latest GCC (4.8):
template<template<template<typename> class> class T> struct test {};
template<template<typename> class T> struct foo {};
test<foo> bar;
Is this an extension, or is the other answer actually incorrect and it is allowed by the standard? If not, is there any particular reason for the omission?
In std::vector<int> the class template std::vector is passed the type int as a parameter. In std::get<42>(some_tuple), the function template std::get is passed the value 42 as a parameter. Perhaps unimaginatively the former kind of argument is called a type argument of a template (or template type argument) while the latter kind is a (template) non-type argument.
But templates can also accept another kind of arguments: other templates. For instance template<template<typename> class T> void foo(); declares a function template taking a template as argument, that itself takes a type argument. (As a note, while templates are not types the term 'non-type argument' still does not cover template template arguments. It is reserved for arguments like template<int NonTypeArgument>.)
Since there is no such thing as a template template in C++ (there are class, function, and alias templates -- but they're collectively simply 'templates' anyway), there is no such thing as a template template template parameter. What you have is a run off the mill template template parameter, where the expected template argument has a template template argument itself. I cannot find a reference in the Standard that forbids this, like the answer you link claims.