I am newbie to c++ template. If I defined a template method, which I found I can call non template method
for example
void non_template(double x)
{
}
template<typename T>
void testClass<T>::method1() {
/*****/
T var1;
//call a nontemplate here using var1
non_template(var1);
}
I am not sure why this can be allowed without any compilation errors; If my var1 is int, will it be wrong?
I am not sure why this can be allowed without any compilation errors; If my var1 is int, will it be wrong?
Template classes and functions work slightly differently from non-templated ones: checking for validity is done in 2 passes - once at definition time, the other at instantiation (when the method is first called) time.
When processing the template function, it checks things like syntax, and type not dependent on the template arguments. If these succeed, it will not complain and store the definition of the template in it's state.
When you try to call (instantiate) the template with a particular set of arguments, it will go back to the definition stored and recheck thing that are dependent on the type of parameters passed in.
So, if I try to call your function with an int, double and a float like:
test_calls.method(5.0); // Works as expected
test_calls.method(5); // Works, because int can be converted to double implicitly.
test_calls.method("Hello"); // Doesn't work, because "non-templated" cannot be call with a char const* argument.
The compiler looks for matches by applying permitted conversions to parameters in order to find a match (i.e. a function that can be called). That is true for all functions, not just templates.
If T is a type that can be implicitly converted to a double, then it will be so the "non template" function can be called.
If T cannot be implicitly converted to double, then the compiler will report it cannot find a match in some way.
Related
How did compiler decide to call bar function without knowing the type of template parameter T of foo function?
Usually when we call foo(2), T is deduced as int based on argument 2.
Here T is deduced based on parameters of function bar to which foo is passed.
#include <iostream>
template<typename T>
void foo(const T& a_) {
std::cout << a_<< std::endl;
}
void bar(void (*ptr) (const int&)) {
std::cout << "bar called" << std::endl;
}
int main() {
bar(foo);
}
compiler: gcc
When you have an overload set like foo, meaning that the result of name lookup for foo results in (potentially multiple) non-template functions or function templates and the overload set has its address or a reference taken (here implicitly by passing it as a function argument), then the compiler will try to do overload resolution against the target type if there is any. The target type here is void(*)(const int&). The whole procedure is specified in [over.over], parts of which I explain below.
The way this works is that the compiler will look at each function and function template in the overload set, will look whether it can match its type against the target type and will then add those functions and function template specializations that match to a set of selected overloads. Afterwards a few more elimination steps are done to reduce the set of selected overloads (e.g. checking whether associated constraints are satisfied and preferring functions over function template specializations, see [over.over]/5 for all details) and hopefully at the end exactly one selected function or function template specialization remains, which will then be chosen as the result of overload resolution that the original name (foo) refers to and from which the address/reference is taken.
For a non-template function a match means that the function type of the target ( void(const int&)) needs to simply be identical to the function's type. But you don't have any non-template overload here.
For a function template the compiler will try to perform template argument deduction to select one specialization of the template that matches the type and can be added to the list of selected overloads. Specifically this works just the same as in template argument deduction of a function call where there is usually a list of function argument/parameter pairs to deduce template arguments from, but in this case (given that there is a target type) the deduction will consider only one argument/parameter pair with the argument being the target type (void(*)(const int&)) and the parameter being the function type of the template containing the template parameters, i.e. here void(const T&), adjusted to a pointer type void(*)(const T&) because the argument is a function pointer type.
So in the end the compiler will perform normal deduction of
void(*)(const int&)
against
void(*)(const T&)
to decide what T should be in the selected specialization. I guess it is pretty obvious that T should be int for the types to match. So the selected specialization will be the one with T = int which has a function type matching the target type and since it is the only selected overload and since it will not be eliminated in any of the further steps, it will be chosen as the result of overload resolution.
It actually deduces the parameter of T from the type of function pointer, how this basically works.
At first compiles sees that you called bar, which accepts function pointer which returns void and takes one argument of const int& type.
Then it sees that passes parameter is function template. Then it starts to wonder if you can instantiate the function so that it's return type and parameter list is in correspondence with whatever the function pointer type is.
Voila. The compiler indeed can achieve this by removing cv qualifiers and references. The T appears to be int.
I am trying to understand how template argument deduction works in C++. And so writing out different examples. One such example which doesn't work and i can't understand why is given below:
#include<iostream>
template<int var, typename T>
void func (T x)
{
std::cout<<x<<std::endl;
}
template<typename T>
void SomeFunc(T a)
{
a(6);
}
int main()
{
func<5, int>(10);//this work as expected
func<5>(20);//this works as well using template argument deduction
SomeFunc(func<5,int>) ;//this works as well
//the next two calls doesn't work
SomeFunc(func<5>);//this doesn't work. Why doesn't template argument deduction works here
SomeFunc(func<5>(20));//this doesn't work either.
return 0;
}
In the above example, the statement SomeFunc(func<5>); doesn't work. My thinking is that when the compiler tries to instantiates SomeFunc<> it needs its template type parameter. But we have passed func<5> as the function call argument without actually calling(specifying the call argument to func itself) func so there is no way to deduce the second parameter and so it doesn't work. My first question is that is my analysis of why this call fails correct? If not then why doesn't it work.
Next in the statement SomeFunc(func<5>(20)); i have specified the function call argument 20 to func which was not specified in the previous call. But still this statement doesn't work. Why is this so?
While reading about template argument deduction i also came across the following statement:
Deduction only works for immediate calls.
But i could not understand what the above quoted statement means. It may have to do something with the fact that complete type or incomplete type used as template argument but i am not sure.
func<5> is an invalid call to func since you must use parentheses to call a function even for functions that take 0 parameters. As for the second error, func<5>(20) is valid since the compiler is able to deduce T from the function's parameter type. However, you cannot have void variables. Thus, calling SomeFunc with a void value is invalid, since a cannot be a void parameter.
static_assert(std::is_same_v<decltype(func<5>(20)), void>);
SomeFunc(func<5>(20)); // T is deduced as void
SomeFunc(func<5,int>);
You pass a pointer to the function func<5,int> and T becomes void(*)(int) which is fine. It also works inside SomeFunc when you use the function pointer a to call the function it is pointing at.
SomeFunc(func<5>);
Deduction is not possible. The compiler is not able to look forward to see that inside SomeFunc you will call a(6) so therefore it must instantiate func<5,int> and make a point at it.
SomeFunc(func<5>(20));
Here you actually call func<5,int> (with the argument 20) and pass the return value from that call into SomeFunc. There is no return value from func<5,int> since it's void and void a; is not valid. If it had been valid, the next problem would have been that you try to call a in SomeFunc. The argument to SomeFunc must be a callable of some sort or else a(6); will fail.
I'm a little confused as to what is required regarding calling templated functions in C++11, where default values are supplied for the template arguments.
For example, say I have the following templated function
template <class T = double> void foo()
{
/* Do something */
}
and I want to call it somewhere in my code. Are all of these valid calls?
foo(); //Is this OK?
foo<>();
foo<int>();
It compiles fine with GCC 4.7.2, but I'm not sure if it's strictly correct C++. I guess my uncertainty may come from the requirement to use empty angle brackets <> when creating an instance of a templated class using the default template, as described here:
Template default arguments
but I presume in my case having the function brackets () is the critical difference?
A function call to a function template where every template parameter is deducible or has a default can use empty angle brackets or can omit them, both ways are valid.
The difference is that if you omit the angle brackets, you're inviting overload resolution to also consider non-template functions that happen to be named foo and happen to be callable with the same (empty in this case) parameter list.
This hasn't changed in C++11.
Without knowing a function's type, I am declaring its pointer with below technique and initializing a function pointer.
template<typename T>
struct Declare { typedef T Type; }; // for declaring any func ptr
void fun () {}
int main ()
{
Declare<fun>::Type pf = &fun; // can't use C++0x 'auto'
}
However, it gives compile error as, error: expected a type, got ‘fun’. Though the type of any method is known at compile time. Is it invalid to pass a function into a class template as above ?
[Note: replacing fun with void (*)() works fine. But that's not what want.]
Is it invalid to pass a function into a class template as above ?
Totally yes, you're mixing up type and non-type parameters.
fun is a non-type argument, it's an address of a function, like an arbitary number 0x12345678.
typename T is a type parameter. You can only pass it types, like int,MyClass, double (*)(std::string), void (MyClass::*)().
You'll just have to life with the fact, that you need compiler support for that stuff or some really ugly trickery to deduce the type.
If you're in for the trickery, there's Boost.Typeof for non-C++0x coder like you. It also provides a stand-in for auto with BOOST_AUTO, but that is only a short way for writing BOOST_TYPEOF:
int hello(){ return 42; }
BOOST_AUTO(var1,hello()); // type of var1 == int
BOOST_TYPEOF(hello()) var2 = hello(); // same
The problem? You need to help it for every user-defined type you have. See this Ideone example.
Now, most of the time I don't think you need Boost.Typeof. Why? Because if you use a function, you of course need to know the signature, how would you pass the correct arguments otherwise? Or use the return type in a correct way?
The other times are the usage in templates anyways. If you declare a function pointer like auto fptr = &func, then you have the knowledge, that func exists, aka you know its signature and type. For when you don't know that func exists, you need it passed to you anyways, preferably in a template:
template<class FPtr>
void myfunc(FPtr otherfunc){
// use otherfunc
}
And with a template you have the knowledge of that functions type again.
Is it invalid to pass a function into a class template as above?
Yes. Because what you, in other words, want the compiler to deduce the type parameter for the class template, which simply not possible in C++. Recall that fun itself isn't a type, its a value of type void (*)(). But your class template expects type, not value. That's why it wouldn't work.
Type deduction is possible with functions only, that means even with the constructor of class. So if you write a templated constructor, and then you can write this:
Declare obj(&fun);
Here the type of the function is known as long as you're in constructor, once you exist from it, you lost the information. So what you probably need is : define a class, say, AbstractFunctor (possibly class template) and derived from it defining an another class say template<Fun fun> struct Functor. Then you can create an instance of Functor which can remember the function type forever, and store the instance in AbstractFunctor* as a member data of Declare.
But I think, even in this way, the type cannot be used as Declare::Type or Declare::AbstractFunctor::Type, simply because the type is stored in an instance of the class; only the instance knows the type. So the getting type using syntax like A::Type is out of the question. And you cannot get type using syntax instance.Type either. All you can do is : call the function, using the instance, like a functor.
EDIT:
If you're allowed to use C++0x's other features (excluding auto), then the problem has a trivial solution:
Declare<decltype(&fun)>::Type pf = &fun;
pf(); //call the function
Demo : http://ideone.com/
But then, you don't need even Declare, as you can do this instead:
decltype(&fun) pf = &fun;
pf(); //call the function
If we've this function template,
template<typename T>
void f(T param) {}
Then we can call it in the following ways,
int i=0;
f<int>(i);//T=int : no need to deduce T
f(i); //T=int : deduced T from the function argument!
//likewise
sample s;
f(s); //T=sample : deduced T from the function argument!
Now consider this variant of the above function template,
template<typename TArg, typename TBody>
void g(TArg param)
{
TBody v=param.member;
}
Now, can the compiler deduce the template arguments if we write,
sample s;
g(s); //TArg=sample, TBody=int??
Suppose sample is defined as,
struct sample
{
int member;
};
There are basically two questions:
Can the compiler deduce the template arguments in the second example?
If no, then why? Is there any difficulty? If the Standard doesn't say anything about "template argument deduction from function body", then is it because the argument(s) cannot be deduced? Or it didn't consider such deduction so as to avoid adding more complexity to the language? Or what?
I would like know your views on such deduction.
EDIT:
By the way, the GCC is able to deduce function arguments if we write this code:
template<typename T>
void h(T p)
{
cout << "g() " << p << endl;
return;
}
template<typename T>
void g(T p)
{
h(p.member); //if here GCC can deduce T for h(), then why not TBody in the previous example?
return;
}
Working demonstration for this example : http://www.ideone.com/cvXEA
Not working demonstration for the previous example: http://www.ideone.com/UX038
You probably already concluded that the compiler won't deduce TBody by examining the type of sample.member. This would add yet another level of complexity to the template deduction algorithm.
The template matching algorithm only considers function signatures, not their bodies. While not used too often, it's perfectly legal to simply declare a templated function without providing the body:
template <typename T> void f(T param);
This satisfies the compiler. In order to satisfy the linker, you must of course also define the function body somewhere, and ensure that all required instantiations have been provided. But the function body does not necessarily have to be visible to client code of the template function, as long as the required instantiations are available at link time. The body would have to explicitly instantiate the function, eg:
template <> void f(int param);
But this only partially applies to your questions, because you could imagine a scenario like the following, where a 2nd parameter could be deduced from the a provided default parameter, and which won't compile:
template<typename TArg, typename TBody>
void g(TArg param, TBody body = param.member); // won't deduce TBody from TArg
The template matching algorithm considers only the actual type, not any potential nested member types in case of classes or structs. This would have added another level of complexity which apparently was judged to be too complex. Where should the algorithm stop? Are members of members, and so forth, also to be considered?
Also, it's not required because there are other means of achieving the same intention, as shown in the example below.
Nothing prevents you from writing:
struct sample
{
typedef int MemberType;
MemberType member;
};
template<typename TArg>
void g(TArg param)
{
typename TArg::MemberType v = param.member;
}
sample s = { 0 };
g(s);
in order to obtain the same effect.
Regarding your sample you added after editing: whereas it seems that h(p.member) does depend on the member of the struct, and hence the template matching algorithm should fail, it doesn't because you made it a two-step process:
Upon seeing g(s);, the compiler looks for any function taking an argument of type sample (templated or not!). In your case, the best match is void g(T p). At this point, the compiler has not even looked at the body of g(T p) yet!.
Now, the compiler creates a instance of g(T p), specialized for T: sample. So when it sees h(p.member) it knows that p.member is of type int, and will try locate a function h() taking an argument of type int. Your template function h(T p) turns out to be the best match.
Note that if you had written (note the NOT_A_member):
template<typename T>
void g(T p)
{
h(p.NOT_A_member);
return;
}
then the compiler would still consider g() a valid match at stage 1. You then get an error when it turns out that sample does not have a member called NOT_A_member.
There are a couple of things that the compiler cannot possibly do with the code that you provide, the first of which is deduce the second template argument TBody. First, type deduction is only applied to the arguments of the function when the compiler is trying to match the call. At that point the definition of the templated function is not even looked at.
For extra credits, even if the compiler were to look the function definition, the code TBody v = parameter.member is non-deducible in itself, as there are potentially infinite data types that can accept a parameter.member in the constructor.
Now, on the second block of code. To understand it the whole process of template compilation starts when the compiler sees the function call g(x) at that point of call. The compiler sees that the best candidate is the template function template <typename T> void g( T ) and determines what the type T is as part of the overload resolution. Once the compiler determines that it is a call to the template, it performs the first pass of compilation on that function.
During the first pass, syntactic checks are perform without an actual substitution of the type, so the template argument T is still any-type and the argument p is of a yet-unknown type. During the first pass, the code is verified, but dependent names are skipped and their meaning is just assumed. When the compiler sees p.member, and p is of type T that is a template argument it assumes that it will be a member of the yet unknown type (this is the reason why if it is a type you would have to qualify it here with typename). The call h(p.member); is also dependent on the type argument T and is left as it is, assuming that once the type substitution takes place everything will make sense.
Then the compiler does actually substitute the type. At this step T is no longer a generic type, but it represents the concrete type sample. Now the compiler during the second pass tries to fill in the gaps that were left during the first pass. When it sees p.member it looks member inside the type and determines that it is an int and tries to resolve the call h( p.member ); with that knowledge. Because the type T has been resolved before this second stage, this is equivalent to the outside call g(x): all types are known and the compiler only needs to resolve what is the best overload for a function call h that takes an argument of type int&, and the whole process starts again, the template h is found as the best candidate, and ...
It is really important for metaprogramming to understand that type deduction is performed only on the actual signature of the function and not the body, and that is what makes it non-trivial for beginners. Using enable_if (from boost or elsewhere) in the function signature as argument or return type is not a coincidence, but the only way of having the compiler fail to substitute the type before the template is selected as best candidate and the substitution failure is turned into an actual error (and not SFINAE)
No compiler could possibly implement this functionality in a consistent manner. You are simply asking too much.
TBody might be ambiguous, because sample might not be the only type that has a member member. Furthermore, if g calls other template functions, the compiler has no way of knowing what other restrictions might be imposed on TBody.
So in some edge cases, it is theoretically possible to deduce the proper type for TBody, generally it is not.