Is this correct behavior of template? - c++

template<class blah, class bleh>
blah func(bleh p)
{
// Do something
}
int main()
{
double d=1.111;
int i = func<int>(d); // #1
int j = func<int,double>(d); // #2
// ....
}
In this example both the instances of func, #1 and #2 are compiling, but I'm unsure of what is correct, and why.
Can some one explain why #1 is correct, and maybe give some background?

Yes, this is correct behaviour.
Case 1 - type deduction
func<int>(d);
This uses template type deduction to determine the type for bleh.
In order to instantiate a function template, every template argument must be known, but not every template argument has to be specified. When possible, the compiler will deduce the missing template arguments from the function arguments. This occurs when a function call is attempted and when an address of a function template is taken.
The compiler sees the type for d as being a double and thus deduces the actual type for bleh must also be a double.
From cppreference, also covered in § 14.8.2 of the C++ specification;
Template argument deduction attempts to determine template arguments ..., which can be substituted into each parameter P to produce the type deduced A, which is the same as the type of the argument A, ... .
If there are multiple parameters, each P/A pair is deduced separately and the deduced template arguments are then combined. If deduction fails or is ambiguous for any P/A pair or if different pairs yield different deduced template arguments, or if any template argument remains neither deduced nor explicitly specified, compilation fails.
Case 2
func<int,double>(d);
The type for bleh is explicitly set to double, hence the compiler will make it such. The argument d is provided and since it is also a double, the compiler happily continues. If an argument (i.e. in place of d) was provided with a type that was not a double, or could not implicitly be converted to a double (e.g. via promotions, non-explicit constructors or user provided conversions), this would result in an error.

Related

deducing function template specialization when taking address

I'm trying to understand the rules for function template argument deduction in the case where all arguments are defaulted. Under 13.10.1 (Explicit template argument specification), the standard (C++20) says:
— when the address of a function is taken, when a function initializes a reference to function, or when a pointer to member function is formed, ... If all of the template arguments can be deduced, they may all be omitted; in this case, the empty template argument list <> itself may also be omitted.
However, in the fourth line of the code snippets below, compilers (gcc, MSVC) seem to insist on having the empty angle brackets. Is this non-conformance or have I missed something ? (In this example, the issue doesn't matter, but the question arose in a context where it does matter).
template <typename T = int> void f(T) {}
void (*p)(int) = f; //ok
auto a = f<>; //ok
auto b = f; //error, can't deduce
void g() {}
auto c = g; //OK
The compilers are correct: auto a = f<>; is well-formed and auto b = f; is ill-formed. This is due to the rules about auto, combined with the rules about the address of the function template name f.
As described in [dcl.type.auto.deduct]/4, the auto type for the variable definitions is found in a way like template argument deduction done for a hypothetical function template using a template type parameter in its function parameter:
template <typename U> void auto_deducer(U);
auto a = f<>; // auto becomes the U deduced for auto_deducer(f<>)
auto b = f; // auto becomes the U deduced for auto_deducer(f)
In [temp.deduct.type] paragraphs 4 and 5:
In certain contexts, however, the value [of a template argument] does not participate in type deduction, but instead uses the values of template arguments that were either deduced elsewhere or explicitly specified. If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.
The non-deduced contexts are:
...
A function parameter for which the associated argument is an overload set, and one or more of the following apply:
...
the overload set supplied as an argument contains one or more function templates.
...
So for both a and b, the template argument deduction used to determine the type of auto fails. Since it's not true that "all of the template arguments can be deduced", we're not allowed to omit the empty <> syntax.
But we're not entirely done yet, because the same paragraph [temp.arg.explicit]/4 you quoted has some relevant additional text:
Trailing template arguments that can be deduced or obtained from default template-arguments may be omitted from the list of explicit template-arguments. A trailing template parameter pack.... If all of the template arguments can be deduced, they may all be omitted; in this case, the empty template argument list <> itself may also be omitted. In contexts where deduction is done and fails, or in contexts where deduction is not done, if a template argument list is specified and it, along with any default template arguments, identifies a single function template specialization, then the template-id is an lvalue for the function template specialization.
For the definition of both a and b, the f<> or f expression is in a non-deduced context, so "deduction is not done". (The template argument deduction for the hypothetical auto_deducer(f<>) then fails, but that's for the overall auto_deducer call, after the part actually involving f<> determined that the type deduction step should not be done with that argument at all.) In auto a = f<>;, "a template argument list is specified" and using the default template argument "identifies a single function template specialization" f<int>, so the paragraph's final sentence applies and the template-id names f<int> after all. In auto b = f; no template argument list is specified (and f is not a template-id), so the sentence can't apply.
An actual call like the statement f(); is fine because template argument deduction happens, uses the default template argument, and succeeds without the complication of auto. Converting expression f to a specific target pointer-to-function type is fine, because that will deduce the template parameter T from the target type, and the default template argument doesn't get involved.
Another confirmation this behavior is intended is found in a non-normative note in [over.over]/3. The [over.over] section applies when lookup for a name (like f or f<>) gives an overload set comprising one or more functions and/or function templates and the name expression is not followed by a function call argument list:
For each function template designated by the name, template argument deduction is done, and if the argument deduction succeeds, the resulting template argument list is used to generate a single function template specialization, which is added to the set of selected functions considered. [ Note: As described in [temp.arg.explicit], if deduction fails and the function template name is followed by an explicit template argument list, the template-id is then examined to see whether it identifies a single function template specialization. If it does, the template-id is considered to be an lvalue for that function template specialization. The target type is not used in that determination. - end note ]
Trailing template arguments that can be deduced or obtained from default template-arguments
may be omitted from the list of explicit template-arguments. [...] If all of the template
arguments can be deduced, they may all be omitted; in this case, the empty template argument list <>
itself may also be omitted.
Note the last sentence, as opposed to the first sentence, does not say "deduced or obtained from default template-arguments". Deducing and obtaining from default template-arguments are two different things. This may or may not be a wording defect in the standard.

Why does template substitution fail on a constructor unless I add brackets?

I am trying to understand why substitution fails on the following snippet unless brackets are added:
template<typename T>
struct A {};
template<typename T>
struct B {
B(A<T>);
};
template<typename T>
void example(A<T>, B<T>);
struct C {};
struct D {
D(C);
};
void example2(C, D);
int main(int argc, char *argv[]) {
example(A<int>{}, A<int>{}); // error
example(A<int>{}, {A<int>{}}); // ok
example2(C{}, C{}); // ok
example2(C{}, {C{}}); // ok
return 0;
}
See this example: https://godbolt.org/z/XPqHww
For example2 I am able to implicitly pass the C{} to the constructor of D without any error. For example I am not allowed to implicitly pass the A<int>{} until I add brackets.
What defines this behaviour?
example is a function template and the function parameters depend on the template parameter. Therefore and since you did not specify any template arguments explicitly in the call example(A<int>{}, A<int>{});, when you call this function, template argument deduction is performed to figure out what type T should be for the call.
With a few exceptions template argument deduction requires that a T can be found such that the type of the argument in the function call matches the type in the function parameter exactly.
The issue with your call is that A<int> does clearly not match B<T> exactly for any T (and none of the exceptions apply either), so the call will fail.
This behavior is necessary, because the compiler would otherwise need to test all possible types T to check whether the function can be called. That would be computationally infeasible or impossible.
In the call example2(C{}, C{}); no templates are involved, so no template argument deduction is performed. Because the compiler doesn't need to figure out the target type in the parameter anymore, it becomes feasible to consider implicit conversions from the known argument type to the known parameter type. One such implicit conversion is the construction of D from C via the non-explicit constructor D(C);. So the call succeeds with that conversion.
example2(C{}, {C{}}); does effectively the same.
The question then is why example(A<int>{}, {A<int>{}}); works. This is because of a specific rule that can be found e.g. in [temp.deduct.type]/5.6 of the C++17 standard (draft N4659). It says that a function argument/parameter pair for which the argument is an initializer list (i.e. {A<int>{}}) and the parameter is not a specialization of std::initializer_list or an array type (it is neither here), the function parameter is a non-deduced context.
Non-deduced context means that the function argument/parameter pair will not be used during template argument deduction to figure out the type of T. This means its type does not need to match exactly. Instead, if template argument deduction otherwise succeeds, the resulting T will simply be substituted into the non-deduced context and from there implicit conversions will be considered as before. B<T> can be constructed from {A<int>} if T = int because of the non-explicit constructor B(A<T>);.
Now the question is whether template argument deduction will succeed and deduce T = int. It can only succeed if a T can be deduced from another function parameter. And indeed there is still the first parameter, for which the types match exactly: A<int>/A<T> matches for T = int and because this function argument doesn't use an initializer list, it is a context from which T will be deduced.
So indeed for example(A<int>{}, {A<int>{}}); deduction from the first argument will yield T = int and substitution into the second parameter B<T> makes the initialization/conversion B<T>{A<int>{}} succeed, so that the call is viable.
If you were to use initializer lists for both parameters as in example({A<int>{}}, {A<int>{}});, both argument/parameter pairs become non-deduced context and there wouldn't be anything left to deduce T from and so the call would fail for failure to deduce T.
You can make all calls work by specifying T explicitly, so that template argument deduction becomes unnecessary, e.g.:
example<int>(A<int>{}, A<int>{});

convert member function to pointer to member function

Clang,GCC,MSVC have different opinion about conversion of member functions.
Who is right ?
https://gcc.godbolt.org/z/QNsgwd
template<typename T>
struct a
{
template <typename... Args>
void va(Args...) {}
template <typename X>
void x(X) {}
void y(int) {}
};
struct b : a<b>
{
void testva()
{
using F = void (a<b>::*)();
F f = (F)&a<b>::va<int>; // gcc: error, msvc: error, clang: ok
}
void testx()
{
using F = void (a<b>::*)();
F f = (F)&a<b>::x<int>;// gcc: error, msvc: ok, clang: ok
}
void testy()
{
using F = void (a<b>::*)();
F f = (F)& a<b>::y; // gcc: ok, msvc: ok, clang: ok
}
};
testx and testy are well-formed, so gcc is wrong about testx. But the Standard is somewhat vague about testva.
Starting with the easiest, in testy the expression &a<b>::y names a non-template function which is not overloaded, so it has type void (a<b>::*)(int) without need for further analysis. Conversion from any pointer-to-member-function to any other pointer-to-member-function is a well-formed reinterpret_cast with unspecified results except if converted back to the original type, and a C-style cast can do what a reinterpret_cast can do.
For template functions we have [over.over]/1-2:
A use of an overloaded function name without arguments is resolved in certain contexts to a function, a pointer to function or a pointer to member function for a specific function from the overload set. A function template name is considered to name a set of overloaded functions in such contexts. A function with type F is selected for the function type FT of the target type required in the context if F (after possibly applying the function pointer conversion) is identical to FT. The target can be
...
an explicit type conversion ([expr.type.conv], [expr.static.cast], [expr.cast]),
...
If the name is a function template, template argument deduction is done ([temp.deduct.funcaddr]), and if the argument deduction succeeds, the resulting template argument list is used to generate a single function template specialization, which is added to the set of overloaded functions considered. [ Note: As described in [temp.arg.explicit], if deduction fails and the function template name is followed by an explicit template argument list, the template-id is then examined to see whether it identifies a single function template specialization. If it does, the template-id is considered to be an lvalue for that function template specialization. The target type is not used in that determination. — end note ]
So this means we first try template argument deduction for a<b>::x<int>, matching it to the target type void (a<b>::*)(). But there are no specializations that can possibly give an exact match, since they all have one argument, not zero, so deduction fails. But per the note, there's also [temp.arg.explicit] (paragraph 3 in C++17, 4 in the latest C++20 draft):
Trailing template arguments that can be deduced or obtained from default template-arguments may be omitted from the list of explicit template-arguments. A trailing template parameter pack ([temp.variadic]) not otherwise deduced will be deduced as an empty sequence of template arguments. ... In contexts where deduction is done and fails, or in contexts where deduction is not done, if a template argument list is specified and it, along with any default template arguments, identifies a single function template specialization, then the template-id is an lvalue for the function template specialization.
In testx, the template-id a<b>::x<int> identifies a single function template specialization. So it names that specialization, and again the C-style cast is valid with unspecified result.
So in testva, does a<b>::va<int> identify a single specialization? It would certainly be possible to use that expression to name different specializations, via [temp.arg.explicit]/9:
Template argument deduction can extend the sequence of template arguments corresponding to a template parameter pack, even when the sequence contains explicitly specified template arguments.
Except this says "template argument deduction". And here the template argument deduction involved fails, since it required an impossible match with the target type void (a<b>::*)(). So nothing really explains whether a<b>::va<int> identifies a single specialization, since no other method of getting additional template arguments is described, or identifies multiple specializations, since it could be validly used in other contexts with matching target types.
clang is right
[expr.reinterpret.cast]/10
A prvalue of type “pointer to member of X of type T1” can be explicitly converted to a prvalue of a different type “pointer to member of Y of type T2” if T1 and T2 are both function types or both object types. The null member pointer value is converted to the null member pointer value of the destination type. The result of this conversion is unspecified, except in the following cases:
Converting a prvalue of type “pointer to member function” to a different pointer-to-member-function type and back to its original type yields the original pointer-to-member value.
Converting a prvalue of type “pointer to data member of X of type T1” to the type “pointer to data member of Y of type T2” (where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer-to-member value.
&a<b>::va<int> et al. are prvalue of type "pointer to member of a<b> of type void(int)" and converting it (without calling the resulting function pointer whose value is unspecified) is legal.
Let's simplify to this example:
struct a {
template <typename... Args>
void va(Args...) {}
template <typename X>
void x(X) {}
void y(int) {}
};
using no_args = void(a::*)();
using int_arg = void(a::*)(int);
And lets try the following four things:
reinterpret_cast<no_args>(&MEMBER_FUNCTION); // (1)
(no_args) &MEMBER_FUNCTION; // (2)
(no_args) static_cast<int_arg>(&MEMBER_FUNCTION); // (3)
int_arg temp = &MEMBER_FUNCTION; (no_args) temp; // (4)
(Replacing MEMBER_FUNCTION with &a::va<int>, &a::x<int> and &a::y).
clang compiles all of them.
gcc compiles everything except (2) with &a::va<int> and &a::x<int>.
MSVC compiles everything except (1) and (2) with &a::va<int> (but is fine with &a::x<int>).
Notice that (3) is essentially the same as (4).
https://gcc.godbolt.org/z/a2qqyo showing an example of this.
What you can see from this is that &MEMBER_FUNCTION is not resolved to a specific member function pointer in case of templates, but if it is resolved, it is allowed to reinterpret it into another member function pointer type.
What the standard has to say:
[over.over]/1:
A use of an overloaded function name without arguments is resolved in certain contexts to a function, a pointer to function or a pointer to member function for a specific function from the overload set.
A function template name is considered to name a set of overloaded functions in such contexts.
A function with type F is selected for the function type FT of the target type required in the context if F (after possibly applying the function pointer conversion) is identical to FT.
[ Note: That is, the class of which the function is a member is ignored when matching a pointer-to-member-function type.
— end note
 ]
The target can be:
[...]
- an explicit type conversion ([expr.type.conv], [expr.static.cast], [expr.cast])
An example given later on is:
int f(double);
int f(int);
void g() {
(int (*)(int))&f; // cast expression as selector
}
And a few more quotes about templates:
[temp.deduct.funcaddr]/1:
Template arguments can be deduced from the type specified when taking the address of an overloaded function.
The function template's function type and the specified type are used as the types of P and A, and the deduction is done as described in [temp.deduct.type].
[temp.arg.explicit]/4
[...] if a template argument list is specified and it, along with any default template arguments, identifies a single function template specialization, then the template-id is an lvalue for the function template specialization.
This seems like MSVC is right.
&a::va<int> is not resolved unless you assign/cast it to a void(a::*)(int). You should also be able to assign it to void(a::*)(int, char) or void(a::*)(int, double, char), where the Args would be deduced as { int, char } and { int, double, char } respectively. That means that (no_args) &a::va<int> should fail, as there are many possible sets of Args it could be (All of them start with int, and clang overzealously resolves it), and none of them take zero parameters, so (no_args) &a::va<int> is a static_cast that should fail.
As for &a::x<int>, there is only one possible function, so it should work exactly the same way as &a::y (But gcc still hasn't resolved it yet).

Meaning of "deduced A" in the context of type deduction from a call

If P is a class and P has the form simple-template-id, then the transformed A can be a derived class D of the deduced A.
from [temp.deduct.call]4.3
This sentence describes how a function template argument is still valid if it is derived from "deduced A", However, there is not solid definition for what "deduced A" actually is.
My theory is that deduced A is original P with template arguments from A substituted in, but this would break the rules of type deduction trying to find template arguments to make A and deduced A identical, as there would be cases with A being a non-reference and deduced A being a reference.
The goal of function template argument deduction is to figure out which particular specialization of a function template should be used in places where the template name is used like a function name. For example, given a function template
template <typename T>
void f(T* value) {}
when you then have a function call like
int* a = &x;
f(a);
the name f here is not actually the name of a function but the name of a function template. The compiler has to figure out which concrete specialization of the function template this call should actually be calling based on the types of the arguments given in the function call. In other words, it has to figure out which template argument X should be used for the template parameter T to get to an actual function f<X> that could be called here like that. This is a bit of an inverse problem compared to a normal function call. Rather than having to make a list of arguments fit a given signature (by applying conversions), we're now having to make a signature fit a given list of arguments. Another way of looking at it is as trying to deduce template arguments that will make the type of each function parameter match the type of each function call argument. This is what [temp.deduct.call]/4 is talking about here:
In general, the deduction process attempts to find template argument values that will make the deduced A identical to A
Taking our example above, given some deduced template argument X, the deduced argument type is what we get by substituting our deduced X for T into our function parameter type T* (i.e., the type of argument this function parameter takes). If we deduce X to be int, substituting int for T into T* makes our deduced argument type come out to be int*. Since the deduced argument type int* is identical to the type of the actual argument, we've found that the function f<int> is what we were looking for.
To make all of this consistent with how normal function calls behave, there are a few corner cases to take care of. In particular with function call arguments of array and function types, where we normally have array-to-pointer and function-to-pointer decay, as well as top-level const. To deal with this, the standard specifies that the argument type A we're trying to match is not simply taken to be the type of the corresponding function call argument directly but is first transformed by applying the array-to-pointer, function-to-pointer, etc. conversions. This transformed A is the A we're actually trying to make our deduced argument type match. This is just to explain why the standard talks about a "transformed A" there. It's not really that important to the question at hand. The transformed A is just the function argument type we're actually trying to match.
Now, let's say we have some
template <typename T> class B {};
and some derived class
class D : public B<int> {};
When you then have a function template like
template <typename T>
void f(const B<T>*) {}
and a function call like this
D d;
f(&d);
there is no template argument X you could pick for T that would make the deduced argument type const B<X>* equal to D*. But since D is derived from B<int>, deducing the template argument to be int would nevertheless lead to a function specialization f<int> that could take the call. The whole paragraph [temp.deduct.call]/4.3 and especially the sentence from your question
If P is a class and P has the form simple-template-id, then the transformed A can be a derived class D of the deduced A.
is there to allow exactly this to work…

Auto detection of template parameters without arguments

This is an offshoot of an answer to another SO post.
I have the following working code, with the expected output.
#include <iostream>
template <typename T>
T twice(T in)
{
return 2*in;
}
struct Foo
{
Foo operator+(int (*func)(int in)) const
{
Foo ret{data};
ret.data += func(ret.data);
return ret;
}
int data;
};
int main()
{
Foo f1{20};
Foo f2 = f1 + twice;
Foo f3 = f1 + twice<int>;
std::cout << f2.data << std::endl;
std::cout << f3.data << std::endl;
}
I did not know until yesterday that the compiler can deduce the type parameters of a function template even without an argument. In the code above, the expressions
f1 + twice
and
f1 + twice<int>
result in identical values.
My question is: Where in the C++03/C++11 standard can we find the necessary supporting documentation for the compiler's auto type detection logic?
C++11 14.8.2.2 Template arguments can be deduced from the type specified when taking the address of an overloaded function.
Here, the type specified by the parameter type of operator+ is int (*)(int), the overloaded function is twice, so int is deduced as the template argument to give a matching function type. See 14.8.2.5 if you need the gory details of that deduction.
This is closest to the actual c++11 standard but still openly available version of draft I've found: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf.
I believe the template parameter deduction is done when you write Foo f2 = f1 + twice; and pass twice as a function address. twice gets passed as an address of a function to the operator+. I believe the following mechanism kicks in:
14.8.2.2 Deducing template arguments taking the address of a function template
[temp.deduct.funcaddr]:
Template arguments can be deduced from the type specified when taking the address of an overloaded function (13.4). The function template’s function type and the specified type are used as the types of P and A, and the deduction is done as described in 14.8.2.5.
So the actual template deduction will be done basing on the type of the funct. I believe the relevant paragraphs from 14.8.2.5 are 1 and 2.
14.8.2.5 Deducing template arguments from a type [temp.deduct.type]`:
1 Template arguments can be deduced in several different contexts, but in each case a type that is specified in terms of template parameters (call it P) is compared with an actual type (call it A), and an attempt is made to find template argument values (a type for a type parameter, a value for a non-type parameter, or a template for a template parameter) that will make P, after substitution of the deduced values (call it the deduced A), compatible with A.
2 In some cases, the deduction is done using a single set of types P and A, in other cases, there will be a set of corresponding types P and A. Type deduction is done independently for each P/A pair, and the deduced template argument values are then combined. If type deduction cannot be done for any P/A pair, or if for any pair the deduction leads to more than one possible set of deduced values, or if different pairs yield different deduced values, or if any template argument remains neither deduced nor explicitly specified, template
argument deduction fails.
Basically you pass twice as a pointer to the operator+, and then template arguments get deduced via type of the function as defined in operator+. So you have an actual type A that is int (*)(int in) and template types P of twice that gets matched against A and only int twice(int) fits.
I hope I got everything right.