I have following code:
void myfunc()
{
}
template <typename T>
void check()
{
}
template <typename T>
void checkT (T)
{
check<T>();
}
and so if I have in main function a call to checkT(myfunc) then that compiles, but if I have check<myfunc>() that doesn't work although it directly calls the first version. Can you please explain why it is so? The error is
error: no matching function for call to 'check()'
Thanks!
This is because myfunc is a value expression, not a type. You could do
check<decltype(myfunc)>();
though, or equivalently:
check<void(void)>();
See it live on http://liveworkspace.org/code/2ANEre$0
PS. In reply to the comment, I sense a bit of confusion between the function formal parameter and a template type parameter. Make it more explicit by writing:
template <typename T>
void checkT (T somevalue)
{
check<T>(); // note: somevalue is never used!
}
In the first instance checkT(myfunc) it is able to deduce the type, checkT is really identical to checkT( T value ) and so you are passing in value and T is being deduced. In the second case you are not supplying a type you can alter it like so to work:
check<decltype(myfunc)>() ;
you are actually supplying a value where you need a type in this case void(void).
checkT(myfunc) works because myfunc is a value. But the second fails because it is not a type, which the template parameters require. For example,
void checkT(T)
is the same as
void checkT(T t)
so that means the function passed is an object of type T. That is, t is the object and T is the type. In the template parameters of check, it requires an explicit specification of the type, not the object. So thus passing in an object would raise a compilation error. Just like passing in the number 5 where the explicit type int is expected.
You can use it as a type by wrapping it in a decltype expression:
check<decltype(myfunc)>();
// ^^^^^^^^^^^^^^^^
Related
I've got the following code:
template <bool condition>
struct enable_if { };
template <>
struct enable_if<true> { using type = bool; };
template <typename T>
class is_callable {
using Yes = char[1];
using No = char[2];
template <typename U> static Yes& filter(decltype(&U::operator()));
template <typename U> static No& filter(...);
public:
constexpr operator bool() { return sizeof(filter<T>(nullptr)) == sizeof(Yes); }
};
template <typename Lambda, typename enable_if<is_callable<Lambda>{}>::type = true>
void doSomethingWithLambda(Lambda func) {
func();
}
int main() {
doSomethingWithLambda([]() { });
}
The important part is the enable_if<is_callable<Lambda>{}>::type part.
One is forced to instantiate is_callable<Lambda> with {} because if one were to use (), C++ would mistake it for a function call.
Feel free to correct me if I'm wrong, but as far as I know, C++ assumes it is a function in the () case so that the type of expression isn't determined after the time of writing, saving everyone a headache. What I mean by that is, assuming you had a function version and a class version of is_callable (separated by SFINAE using enable_if or something along those lines), the type Lambda could determine the true meaning of (), either a function call or an instantiation. Like I said, as far as I know, C++ wants to avoid this confusion, so it assumes function call and fails if such a function does not exist.
Based on the assumptions above, the following shouldn't work:
enable_if<(bool)is_callable<Lambda>()>::type
What does it matter if I cast the result of the function call (never mind that functions couldn't even be evaluated in this context)? Why is this suddenly treated as an instantiation instead of a function call?
No, your understanding is not correct.
Firstly, a name can't refer to both a class template and a function template. If that happens the program is ill-formed. (And defining both in the same scope is not allowed to begin with.)
Secondly, is_callable<Lambda>() as template argument is not a function call to begin with. It is a function type. It is the type of a function which has no parameters and returns a is_callable<Lambda>.
When the compiler parses a template argument, it can interpret it in two ways: Either as a type or as an expression (or as a braced-init-list), because template parameters can be type parameters or non-type parameters.
When the compiler reads is_callable<Lambda>() it notices that is_callable is a class template and then realizes that is_callable<Lambda> is therefore a type. If you have a type, let's shorten it to T, then T() can either be syntax representing the type of a function returning T and taking no arguments, or it can be an expression formed from one single functional notation explicit cast (which you imprecisely call "instantiation").
There is no way to differentiate these two cases in the context, but the compiler needs to know whether this is a type template argument or a non-type template argument. So there is a rule saying that such ambiguities are always resolved in favor of a type.
If is_callable was a function template instead, there would be no ambiguity, because then is_callable<Lambda> is not a type and therefore is_callable<Lambda>() cannot be a function type. It must be a function call instead and therefore an expression and non-type template argument.
When you write (bool)is_callable<Lambda>() this is not valid syntax for a type and therefore there is no ambiguity. It is a non-type template argument and an expression. And is_callable<Lambda>() is a funcational notation explicit cast because is_callable<Lambbda> is a type. If is_callable was a function template instead of a class template, then it would be a function call.
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.
struct A {};
template<typename T>
void f(int n, T m = 3.14159)
{}
int main()
{
f(8, A{}); // ok
f(8); // error: no matching function for call to 'f'
}
See online demo
Why does the default argument not work in a template function?
EDIT: I also tried following, and wonder why it didn't work as well.
void g(int, auto = 3.14159)
{}
Default function arguments don't affect template argument deduction.
You need a default argument for the template parameter too: typename T = double.
As for void g(int, auto = 3.14159), there seems to be no way to fix it.
In the first case, you gave a value for the second function parameter at the call site, which the compiler could use to deduce the type of the second template argument, which then let it determine which version of the template to instantiate and call.
In the second case, you gave the compiler no information about the type for the second template argument, so it cannot use the template to instantiate the function, and so there is no function with that signature available to call.
The compiler will not use a parameter's default value to deduce a template argument type for that parameter (keep in mind that potentially many choices for the type T could accept a double as a default value).
Given the following templated function:
template <typename T>
void f(std::function <void (T)>) {}
Can I extract T without having to explicitly mention it when calling f?
f<int>([](int){}); works fine but I'd like T to be deduced and f([](int){}); to just work. The latter errors out with "no matching function for call to".
You can deduce T if the object passed into the function actually has type std::function<void(T)>. If the type you pass in is a lambda, then you'll have to deduce it from the type of the lambda's function call operator, like so:
template <class Callable, class Arg, class T>
void f_helper(Callable callable, Ret (Callable::*)(T)) {
// do something with T
}
template <class Callable>
void f(Callable callable) {
f_helper(callable, &callable::operator());
}
Actually, in reality it is a bit more annoying than this, because you need at least two overloads for f_helper, according to whether the lambda is declared mutable (which determines whether operator() is const), and in C++17 you also need to double the number of overloads again according to whether the lambda is noexcept.
The standard library sidesteps issues like this by not attempting to extract the argument type from the callables you pass to algorithms such as std::sort. It just accepts an arbitrary callable type and then tries to call it.
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.