I have a template function, whose type depends on type parameters. The compiler can't deduce template parameter even if it's obvious. This is a basic code and even here it doesn't know it is an int (int is just example). What should be changed to make it work?
#include <iostream>
using namespace std;
template<class T1, class T2>
T1 pr (T2 w) {
return int(w);
}
int main() {
cout<<pr('A'); // your code goes here
return 0;
}
Compiler can only deduce template type arguments only from function arguments types, not from result type. To make it work without changing function template you need to explicitly specify type argument:
cout << pr<int>('A');
But it is probably better to change the definition, since T1 parameter doesn't seem to be useful:
template<class T>
int pr (T w){
return int(w);
}
In C++11 you can use trailing return type, which might be useful in more complex situations:
template<class T>
auto pr (T w) -> decltype(int(w)) {
return int(w);
}
And finally C++14 has return type deduction, so ther it is simply:
template<class T>
auto pr (T w) {
Related
I'm comfortable using templates when they simply parameterize over a type. However, I'm now beginning to use them in more complex applications (specifically, parameterizing over a function, as in C++ Template: typename and function to map to int ), and have been reduced essentially to trial and error (note in the above referenced question I can't get my code to compile).
What are the exact semantics of the template keyword (or the typename keyword when used outside the definition of a template), especially when you want a function as a parameter?
How do I define a template that takes a function as a parameter?
Once defined, how do I instantiate and use that template?
I'll accept the first complete answer that includes both a compilable example as well as clear, full explanation, of what's going on behind the magic?
CLARIFICATION: I understand how to use typename. My question is: What are the exact semantics of template definition, especially when applied to invocable parameters? and How do you define and instantiate a class which takes a function (or functor or something invokable) as a template parameter?
What are the exact semantics of the template and typename keywords, especially when you want a function as a parameter?
template introduces a template declaration (and also declarations of explicit instantiations and specialisations, but that's beyond the scope of this question). It's followed by the list of template parameters, in angle brackets <>.
Within that list, typename or class introduces a type parameter; one of three kinds of parameter, the others being non-type (value) parameters, and template parameters.
How do I define a template that takes a function as a parameter?
The simplest way is with a type parameter, which can be any type that can be called like a function; for example
template <typename F, typename... Args>
void call(F && f, Args &&... args) {f(std::forward<Args>(args)...);}
Once defined, how do I instantiate and use that template?
If it's a function template, simply call the function with appropriately typed arguments. The template parameters will be deduced from them:
void f1(int a, double b); // function
struct fn {
void operator()(std::string);
};
call(f1, 42, 1.5);
call(fn{}, "Hello");
call([](std::string s){std::cout << s}, "Lambda\n");
For class templates, you'd have to specify the function type, which can be a bit messy:
template <typename F>
struct thing {
F f;
};
thing<void(*)(int,double)> thing1 {f1};
thing<fn> thing2 {fn{}};
// Lambdas are problematic since the type has no name
//thing<???> thing3 {[]{std::cout << "Lambda\n";}};
The messiness could be avoided by using a factory function template to deduce the function type and instantiate the class template:
template <typename F>
thing<F> make_thing(F && f) {
return thing<F>(std::forward<F>(f));
}
auto thing1 = make_thing(f1);
auto thing2 = make_thing(fn{});
auto thing3 = make_thing([]{std::cout << "Lambda\n";});
Below some example (commented) code to show how functions can be used in a template. You can replace typename Parameter with typename... Parameter and p to p... if you want the first template to work for any number of fucntion arguments, which uses variadic templates.
#include <functional> // for std::function
#include <iostream>
// example functions
void func(int i)
{
std::cout << "Integer: " << i << ".\n";
}
int gunc(int i)
{
int result = i+1;
std::cout << "+Integer:" << result << ".\n";
return result;
}
// general non-restrictive template
template<typename Function, typename Parameter>
void call_twice(Function f, Parameter p)
{
f(p);
f(p);
}
// Restrict signature to void(int), but the return value can be anything: it will be ignored
void call_thrice(std::function<void(int)> f, int p)
{
f(p);
f(p);
f(p);
}
// Restrict signature to int(int), to exclude func
void call_four_times(std::function<int(int)> f, int p)
{
f(p);
f(p);
f(p);
f(p);
}
int main()
{
call_twice(func, 1); // instantiates void call_twice(void (*)(int), int)
call_twice(gunc, 1); // instantiated void call_twice(int (*)(int), int)
// Note I do not write the explicit types of func and gunc in the above comments, they're not important!
call_thrice(func, 10); // converts func to a std::function<void(int)>
call_thrice(gunc, 10); // return value can be ignored, so int(int) is convertible to void(int)
//call_four_times(func, 100); // will fail to compile: cannot convert a function of signature void(int) to one with signature int(int)
call_four_times(gunc, 100); // converts gunc to std::function<int(int)>
}
Live demo here.
The basic form of a template declaration starts anything of the form
template<typename T>
template<class T> // same as above
template<int N> // explicitly typed template parameter, need not be an int
template<typename... variadic_template_args>
And of course the forms with combinations of the above, including nested template types and all. Just remember the variadic template parameter must come last.
Templates are what the name implies: a blueprint to create a class with certain functionality expressed within the template definition.
Instantiation occurs when you actually call a template function (from either another instantiated template function or a non-template function), or for class templates, when you declare an object of the type, e.g. for std::vector:
std::vector<double> v; // instantiate the class template std::vector for type double
This is no different to templates that take functions as arguments. Note that functions decay to function pointers when passed to another function.
For example, a class template with a function as template parameter:
#include <iostream>
#include <type_traits> // for std::result_of
template<typename Function, Function f>
struct A
{
using function_type = Function;
template<typename... ArgTypes>
typename std::result_of<Function(ArgTypes...)>::type call(ArgTypes... args)
{
return f(args...);
}
};
void func(int i) { std::cout << "Integer: " << i << ".\n"; }
int main()
{
A<decltype(&func), func> a;
a.call(42);
}
Live demo here. Note the extra & in the decltype, because a function only decays to a function pointer when it is passed to a function, not when it is used as a template parameter. Note the "extra" typename before the std::result_of: this is required because its type typedef is a dependent name. These and other times you need to use the template and typename keywords, those are covered in Where and why do I have to put the “template” and “typename” keywords?
It's easier to use lambdas
template <typename F>
void herp(F function)
{
function("Hello from herp");
}
int main()
{
const auto deDerp = [] (const std::string& msg)
{
std::cout << msg << "\n";
};
herp(deDerp);
}
I am playing around with ways to filter types passed to overloaded function templates. I'm using Visual Studio 2013.
Three part question:
Why cant my compiler deduce Blorg3?
Is the reason that TFoo2(argc) generates a compiler error the same as #1?
Is there a way to pass template parameters to a constructor?
Here is the sample code:
#include <type_traits>
#define IFPTR(T,R) typename std::enable_if<std::is_pointer<T>::value, R>::type
#define IFINT(T,R) typename std::enable_if<std::is_integral<T>::value, R>::type
template <class T, IFINT(T, T)* = nullptr> int Blorg1(T n) { return n + 1; }
template <class T, IFPTR(T, T)* = nullptr> int Blorg1(T n) { return *n + 1; }
template <class T> IFINT(T, int) Blorg2(T n) { return n + 1; }
template <class T> IFPTR(T, int) Blorg2(T n) { return *n + 1; }
template <class T> int Blorg3(IFINT(T, T) n) { return n + 1; }
template <class T> int Blorg3(IFPTR(T, T) n) { return *n + 1; }
struct TFoo1 {
template <class T, IFINT(T, T)* _ = nullptr> TFoo1(T n) { }
};
struct TFoo2 {
template <class T> TFoo2(IFINT(T, T) n) { }
};
int main(int argc, char* argv[])
{
Blorg1(argc); // intellisense not happy
Blorg2(argc);
Blorg3<int>(argc); // why cant deduce?
Blorg1(*argv); // intellisense not happy
Blorg2(*argv);
Blorg3<char*>(*argv); // why cant deduce?
(void)TFoo1(argc); // intellisense not happy
(void)TFoo2(argc); // intellisense not happy and !!wont compile!!
return 0;
}
Answer for 1/2 about the reason SFINAE isn't working:
SFINAE and template parameter deduction don't play well together in this context.
Or, they do so long as you're aware of the proper order things happen in.
The deduction must be guaranteed to work to be considered as a possible function to be called in this instance.
Here's a way to look at this in a less technical way:
The compiler searches possible function signatures that match what you're trying to call. [see overload resolution]
If it finds a template parameter, it looks to see if it's valid for deduction.
And this is why you're running into problems. The order in which these two events occur is why what SFINAE works on Blorg1, Blorg2 and TFoo1 but not Blorg3 or TFoo2.
With Blorg3 and TFoo2 the compiler can't slot the parameter you're passing to the template type as it creates a circular dependancy that can't be resolved.
template <class T> int Blorg3(IFINT(T, T) n) { return n + 1; }
template <class T> int Blorg3(IFPTR(T, T) n) { return *n + 1; }
Blorg3<char*>(*argv); // why cant deduce?
To resolve the SFINAE in Blorg3 here requires knowing T. However, T isn't known until the SFINAE is resolved.
The same goes for why TFoo2 doesn't work.
Part 3 - about templates and constructors
Yes, you can pass template parameters to constructors, but only if you do it through deduction such as what was done with TFoo1.
You cannot explicitly pass template parameters to a constructor.
Why cant my compiler deduce Blorg3?
In std::enable_if<std::is_pointer<T>::value, R>::type the ::type refers to a nested name that is dependent on the template parameters T and R. This is a non-deduced context (§14.8.2.5/5), consequently the compiler won't deduce the template argument.
Is that why TFoo2(argc) generates a compiler error?
Yes, a constructor template must be able to deduce its template arguments, and in this case it can't.
Is there a syntax to provide template parameters to a constructor?
No, as I already mentioned, you cannot do so explicitly, they must be deduced, or the template parameters must have default arguments.
I want to write a function such as this:
template<class T1, T2>
T2 getvalue(T1 in)
{
T2 tmp;
// do some work here
return T2;
}
and call in this way:
float x[100];
int x=getvalue<int>(x);
But it seems that I can not do this. The idea is that compiler detect the T1 from usage but I define the return type. But the above code generate an error.
Any suggestion on how I can do this?
When you specify function template arguments explicitly, they're filled in from the left; all remaining arguments are deduced. So you have to write it like this:
template <typename T, typename U>
T getvalue(U in)
{
return in;
}
Usage:
auto x = getvalue<int>(1.5); // x is an "int", and U is deduced as "double"
First off, you have a typo. In your return statement, you're attempting to return a type, not a name. Change:
return T2;
to:
return tmp;
Second, you have a further syntax error in your template parameter list. You need either class or typename to precede each and every template parameter name (I prefer typename, but that's me):
template<typename T1, typename T2>
Finally, you can get deduction to work as you wish by making the return type the first template parameter:
template<typename T1, typename T2>
T1 getvalue(T2 in)
{
T1 tmp;
// do some work here
return tmp;
}
Decuction will now work as you expect:
bool b = getValue <bool> (42.0);
The reason for this is template parameters are evaluated from left to right, not in arbitrary order. The compiler will attempt to deduce any template parameters not specified once the left-most ones have been applied.
good question, templates can get tricky in C++.
correctly written version:
template<typename T1, typename T2>
T2 getvalue(T1 in)
{
T2 tmp;
// do some work here with tmp
return tmp;
}
Correct way to calling per your example:
float x[100]; //array of 100 floats. depending on your application, best practice would suggest to initial the values in the array to 0.
int x=getvalue<double, int>(3.5); //note int x is different than float x[].
Your function is currently returning an int. if you want to return an array of floating point number, your template argument should reflect that as well.
best to always specify both template parameters. remember function templates cannot be partially specialized unlike class templates(only fully)
just my $0.02
Let’s say I have a template function, assign(). It takes a pointer and a value and assigns the value to the pointer’s target:
template <typename T> void assign(T *a, T b) { *a = b; }
int main() {
double i;
assign(&i, 2);
}
In this case I always want T to be deduced from the first argument, but it looks like I didn’t do a good job of expressing this. 2’s type is int, so:
deduce.cpp:5:5: error: no matching function for call to 'assign'
assign(&i, 2);
^~~~~~
deduce.cpp:1:28: note: candidate template ignored: deduced conflicting types for parameter 'T' ('double' vs. 'int')
template void assign(T *a, T b) { *a = b; }
Is there a way I can declare assign() so that the second argument doesn’t participate in template parameter deduction?
Using two type parameters is probably the best option, but if you really want to perform deduction only from the first argument, simply make the second non-deducible:
template<typename T>
void assign( T* a, typename std::identity<T>::type b );
Demo: http://ideone.com/ZW6Mpu
An earlier version of this answer suggested using the template alias feature introduced in C++11. But template aliases are still a deducible context. The primary reason that std::identity and std::remove_reference prevents deduction is that template classes can be specialized, so even if you have a typedef of a template type parameter, it's possible that another specialization has a typedef of the same type. Because of the possible ambiguity, deduction doesn't take place. But template aliases preclude specialization, and so deduction still occurs.
The problem is that the compiler is deducing conflicting information from the first and the second argument. From the first argument, it deduces T to be double (i is a double); from the second one, it deduces T to be int (the type of 2 is int).
You have two main possibilities here:
Always be explicit about the type of your arguments:
assign(&i, 2.0);
// ^^^^
Or let your function template accept two template parameters:
template <typename T, typename U>
void assign(T *a, U b) { *a = b; }
In this case, you may want to SFINAE-constraint the template so that it does not partecipate to overload resolution in case U is not convertible to T:
#include <type_traits>
template <typename T, typename U,
typename std::enable_if<
std::is_convertible<U, T>::value>::type* = nullptr>
void assign(T *a, U b) { *a = b; }
If you do not need to exclude your function from the overload set when U is not convertible to T, you may want to have a static assertion inside assign() to produce a nicer compilation error:
#include <type_traits>
template<typename T, typename U>
void assign(T *a, U b)
{
static_assert(std::is_convertible<T, U>::value,
"Error: Source type not convertible to destination type.");
*a = b;
}
It's just that the value 2 is deduced to the type int, which doesn't match the template parameter deduced by &i. You need to use the value as a double:
assign(&i, 2.0);
Why not just use two independent parameter types, one for the source and one for the destination?
template <typename D, typename S> void assign(D *a, S b) { *a = b; }
int main(int argc, char* argv[])
{
double i;
assign(&i, 2);
return 0;
}
If the assignment is not possible, the template instantiation won't compile.
My attempt would look something like this:
template<typename T, typename U>
typename std::enable_if< std::is_convertible< U&&, T >::value >::type // not quite perfect
assign( T* dest, U&& src ) {
*dest = std::forward<U>(src);
}
the second argument is anything you can convert to a T, but we take it by universal reference and conditionally move it into *dest. I test for convertability in the signature rather than have the body fail to compile, because failure-to-find-an-overload seems more polite than failing to compile-the-body.
Live example.
Compared to the simpler:
template<typename T>
void assign( T* dest, typename std::identity<T>::type src ) {
*dest = std::move(src);
}
the above saves 1 move. If you have an expensive to move class, or a class that is copy-only and expensive to copy, this could save a significant amount.
C++20 has std::type_identity which can be used to establish a non-deduced context:
#include <type_traits>
template <typename T>
void assign(T *a, std::type_identity_t<T> b) {
*a = b;
}
int main() {
double i;
assign(&i, 2);
}
Demo
Alternatively, you can use decltype to typecast the second argument to be the type of first.
template <typename T> void assign(T *a, T b) { *a = b; }
int main() {
double i;
assign(&i, (decltype(i))2);
}
Apparently std::identity is not there anymore (Is there a reason why there is not std::identity in the standard library?)
But you can specify the parameter type in the parameter type list, when calling the function:
template <typename T> void assign(T *a, T b) { *a = b; }
int main() {
double i;
assign<double>(&i, 2);
}
In this way the compiler will convert the integer input argument to double to match the function template, without argument deduction.
Live demo
template<typename T>
Ref<Iterator<T> > GetFilterIterator(Ref<Iterator<T> > i, boost::function<bool(T)> pred) {
return new FilterIterator<T>(i, pred);
}
Ref<Iterator<CWorm*> > x = GetFilterIterator(worms(), &CWorm::getLocal);
And worms() returns a Ref<Iterator<CWorm*> Ref> and there is bool CWorm::getLocal(); (which is a member function). And:
template<typename T> struct Ref {
// ...
};
template<typename T> struct Iterator {
// ...
};
This will fail to deduce the template argument:
Iter.h:272:27: note: candidate template ignored: failed template argument deduction [3]
Why?
If I call it with the specified template argument, i.e. GetFilterIterator<CWorm*>(worms(), &CWorm::getLocal), it doesn't complain. I wonder why it cannot deduce the template argument like this. And can I make it different somehow so that it would be able to automatically deduce the type?
Do you mean typname Iterator<T>::Ref for the type of the first parameter in the GetFilterIterator template declaration? If so, that is not a deducible context for template type parameters.
Consider:
template<>
struct Iterator<Foo> {
typedef int Ref;
};
template<>
struct Iterator<Bar> {
typedef int Ref;
};
GetFilterIterator(int(0),f);
Both Iterator<Foo>::Ref and Iterator<Bar>::Ref match the parameter passed to GetFilterIterator, an int. Which one should it pick? C++ disallows deducing template types from parameters like the one you've declared.
With the update to your question it looks like you do mean ::Ref<Iterator<T> >. I think that should be deducible then, and since the typedef Iterator<CWorm*>::Ref is ::Ref<Iterator<CWorm*> > it seems like it should be able to deduce T. I'm not sure why it's not working.
The compiler cannot deduce the template arguments because fitting to the parameters would mean a non-trivial conversion - first to Iterator<T> and then to Ref<Iterator<T> > which both require user-defined conversions. Also, directly converting the member function pointer to boost::function is similarly non-trivial for the compiler.
IBM has a list of supported template parameter deductions.
If you want your template arguments to be deduced automatically, you have to provide wrapper methods:
template <typename T>
Ref<Iterator<T> > makeIteratorRef(T val) {
return Ref<Iterator<T> >(Iterator<T>(val));
}
template <typename T>
boost::function<bool (T)> makeFn(bool (T::*fn) () const) {
boost::function<bool (T)> res = boost::bind(fn, _1);
return res;
}
...
Ref<Iterator<CWorm*> > x = GetFilterIterator(makeIteratorRef(worms()), makeFn(&CWorm::getLocal));
This way the compiler is capable of deducing the template parameters because no conversions are necessary.
By the way, I think you are overcomplicating simple things:
for (auto it = worms().begin(); it != worms().end(); ++it)
if (it->isLocal()) {
// Do something
}
This code is way more readable in C++ and even though it might not be as general it hardly makes the code worse.
Thanks to the hint from Xeo to here about that implicit type conversions are not allowed when deducing template arguments, I wondered wether the second parameter might cause problems here. I thought that it would do the type deduction from left to right and once the type is deducted, it is not a problem anymore (for the function pointer to boost::function cast).
It seems I was wrong and this was exactly the problem.
Another version of the same thing avoids the problem:
template<typename T>
struct PartialFuncWrapper {
::Ref<Iterator<T> > i;
PartialFuncWrapper(::Ref<Iterator<T> > _i) : i(_i) {}
typename Iterator<T>::Ref operator()(boost::function<bool(T)> pred) {
return new FilterIterator<T>(i, pred);
}
};
template<typename T>
PartialFuncWrapper<T> GetFilterIterator(::Ref<Iterator<T> > i) {
return PartialFuncWrapper<T>(i);
}
Then I can write:
Ref<Iterator<CWorm*> > x = GetFilterIterator(worms())(&CWorm::getLocal);