I am learning function templates just now and I wanted to research a bit rules of function templates instantiation. So I've written the following code:
#include <iostream>
template <typename>
int check(int x) {
return x * 2;
}
int main() {
std::cout << check<double>(10) << std::endl; // #1
std::cout << check<>(10) << std::endl; // #2
std::cout << check(10) << std::endl; // #3
return 0;
}
The lines #1, #2 and #3 are not compiled all together, each try I leave only one of them and comment the rest.
So, when #1 is enabled, I have no compilation errors and the correct answer "20" is printed. As I understand, "check<"double">" invokes template instantiation mechanism so "int check(int)" function is really created (the type of template parameter doesn't have any influence).
When #3 is enabled, I have a compilation error "error: no matching function for call to 'check(int)'", which is reasonable, since I am trying to call to "check(int)" function which doesn't exist. My question is regarding #2 case: in this case I get the same "error: no matching function for call to 'check(int)'". Shouldn't call "check<>(10)" trigger template instantiation mechanism as well?
You don't put any template parameter in the <>. How can compiler know which template function to instantiate? Please notice that your template function is:
template <typename>
int check(int x)
If you change it to this:
template <typename T>
int check(T x)
then check<>(10) should be fine because the complier can know the type from the parameter.
I have to say that usually template doesn't go that way:(
Try this one:
template<typename T>
T check(T x){
return x*2;
}
The only template instantiation you'll get is with
check<double>(10)
The others don't instantiate the template. Also for the full power of function templates include the template argument as
template<typename T>
T check(T x) {
return x*2;
}
Then using the power of template argument deduction you can call
check(10.0); // instantiates check<dobule>
check(3); // instantiates check<int>
or
a = MyObject();
check(a); // instantiates check<MyObject>
#2 would be valid if the template argument could be deduced.
#include <iostream>
template <class T>
void foo(T t)
{
std::cout << "Template " << t << '\n';
}
void foo(int n)
{
std::cout << "Not template " << n << '\n';
}
int main()
{
foo(10); //calls non-template function
//because matching non-template preferred over function templates
foo<>(10); //calls the template function, empty brackets indicate you want
//the template overload, type is deduced from passed argument.
}
Another possibility, if the function template had default arguments (only legal in C++11).
template <class T = void>
int foo()
{
return 10;
}
int main()
{
return foo<>(); //same as foo<void>();
}
If you don't pass a template argument, it is equivalent to looking for the function without a template argument (i.e. it doesn't instantiate the template). The added <> means nothing in this case because there are is no overloading.
Since the function you have doesn't actually use the template for anything and the compiler thus can't infer the type T, but if you write it like this:
template <typename T>
T check(T x) {
return x * 2;
}
Then all 3 cases will work, since it infers the type T. See https://stackoverflow.com/a/797632/888641 for more explanation.
Note: You can use typename or class, they do the exact same thing here.
Related
I wrote a trivial example, which is somehow compiles.
#include <iostream>
using namespace std;
template <int A>
void func()
{
cout << 1 + A << endl;
return;
}
int main()
{
// I can not even use this strange func()
int a = 1; func(a); // this does not compile
func(1); // this does not compile as well
return 0;
}
This example frustrates me a lot:
First, I gave non-type template parameter to template, but did not provide any parameters (in parentheses) to function itself. Looks like template parameter becomes the function parameter, but why?
Second, even though it compiles, I can not find a way to use this template, see my comments in main.
And third, what is the reason for existence of template functions with non-type template parameter of integral type? How is it any different from having a regular function?
int A is not a function parameter, it's a template parameter. func takes no arguments and you instantiate/call it like this:
func<1>(); // compile-time constant needed
Please review C++ function templates. You can't use template parameters in the way you want.
On the other hand, having a type template parameter and one function parameter:
template <typename A>
void func(A a)
{
cout << 1 + a << endl;
}
will make your program valid. Maybe that's what you wanted.
Edit:
To your request, here's a usage of such non-type function template parameter:
template <size_t S>
void func(const int (&array)[S])
{
cout << "size of the array is: " << S << endl;
}
or std::array version:
template <size_t S>
void func(std::array<int, S> const& array)
{
cout << "size of the array is: " << S << endl;
}
S here is deduced to the size of the passed array.
Please help to understand below 3 different syntax's
#include <iostream>
using namespace std;
template <typename T>
class Demo {
public:
void print_type(){
if(is_same<int,T>())
cout << "Int type" << endl;
if(is_same<float,T>())
cout << "float type" << endl;
}
};
//1. fun
template<typename T>
void fun(Demo<T> a){
cout << "In <T>fun(Demo<T>)" <<endl;
a.print_type();
}
//2. fun
template<typename T=int,class D=Demo<T> >
void fun(D a){
cout << "In <T,class>fun(Demo)" <<endl;
a.print_type();
}
// 3. fun
template<typename T=int,template <typename T> class D=Demo >
void fun(D<T> a){
cout << "In <T,template>fun(Demo<T>)" <<endl;
}
int main()
{
fun(Demo<int>());
fun(Demo<float>());
return 0;
}
the function calls in main are calling the first version of fun
if I comment out any two definitions of fun, the third one is called
What is the difference between the three fun definitions? How can I call all 3 without commenting out any of them?
Let's take a look at our three functions:
template <typename T> void fun(Demo<T> ); // (1)
template <typename T, typename D> void fun(D ); // (2)
template <typename T, template <typename> class D> void fun(D<T> ); // (3)
Let's consider the second. D will be deduced from the first argument, but T does not appear in any of the function parameters - it is a non-deduced context. As such, it must be specified explicitly by the caller in order to be considered. You do not specify it, so it's a deduction failure and is thrown out of the overload set.
Now (1) and (3) are both viable candidates for arguments of type Demo<int> and Demo<float>. In both cases, the two functions take identical arguments that are exact matches for the caller and are both function templates - so the last tiebreaker is to consider which function template is more specialized (this is also called function template partial ordering). (1) can only accept types that look like Demo<T>. (3) can accept Demo<T> but also OtherTemplate<T> or YetAnotherClass<T>. It's more generic - so we prefer to call (1). The rules for this are pretty complicated, but you can do more searching if you're interested. A simpler example might be:
template <typename T> void foo(T ); // (4)
template <typename T> void foo(T* ); // (5)
foo(new int(42));
Both candidates are viable, (4) matches with T = int* and (5) matches with T = int. But (4) matches anything whereas (5) only matches pointers, which makes it more specialized and thus the best viable candidate.
If you comment out (2), nothing changes - it wasn't a viable candidate anyway. But if you comment out (1), then we call (3) because (3) becomes the only viable candidate (and thus, trivially, the best viable candidate).
I am trying to write some functionality where I need to save different functions and later extract their arguments' types. So I'm using the function signature as template parameter. But I get somewhat unexpected results.
Here's the code:
#include <functional>
#include <iostream>
template <class T>
struct foo
{
foo()
{
std::cout << "class T" << std::endl;
}
};
template <class Ret, class Arg>
struct foo<Ret(Arg)>
{
foo()
{
std::cout << "Ret(Arg)" << std::endl;
}
};
template <class T>
void save(std::function<T>)
{
new foo<T>();
}
int main(int argc, char* argv[])
{
std::function<void(void)> someFoo;
save(someFoo);
return 0;
}
So if the variable someFoo is a function with type void(void), it instantiates the first template, foo<T>. But if I change it to void(int), than I get the desired specialized template instantiated. Why is that?
In C++, having a void argument is actually the same as having no argument at all (unlike in C, by the way). So it would match a specialization for Ret(), but it can't match a specialization for Ret(Arg).
void(void) is the exact same as void() - the second void is optional and makes no difference.
That's why the first template with no parameters is used.
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 have a visitor class resembling this:
struct Visitor
{
template <typename T>
void operator()(T t)
{
...
}
void operator()(bool b)
{
...
}
};
Clearly, operator()(bool b) is intended to be a specialization of the preceding template function.
However, it doesn't have the template<> syntax that I'm used to seeing before it, declaring this as a template specialization. But it does compile.
Is this safe? Is this correct?
Your code is not a template specialization, but rather a non-templated function. There are some differences there. The non-templated operator() will take precedence over a templated version (for an exact match, but type conversions will not take place there) but you can still force the templated function to be called:
class Visitor
{
public: // corrected as pointed by stefanB, thanks
template <typename T>
void operator()( T data ) {
std::cout << "generic template" << std::endl;
}
void operator()( bool data ) {
std::cout << "regular member function" << std::endl;
}
};
template <> // Corrected: specialization is a new definition, not a declaration, thanks again stefanB
void Visitor::operator()( int data ) {
std::cout << "specialization" << std::endl;
}
int main()
{
Visitor v;
v( 5 ); // specialization
v( true ); // regular member function
v.operator()<bool>( true ); // generic template even if there is a non-templated overload
// operator() must be specified there (signature of the method) for the compiler to
// detect what part is a template. You cannot use <> right after a variable name
}
In your code there is not much of a difference, but if your code needs to pass the template parameter type it will get funnier:
template <typename T>
T g() {
return T();
}
template <>
int g() {
return 0;
}
int g() {
return 1;
}
int main()
{
g<double>(); // return 0.0
g<int>(); // return 0
g(); // return 1 -- non-templated functions take precedence over templated ones
}
What you have here is function overloading; to obtain template specialization, you indeed need the template <> syntax. However, you should be aware that these two approaches, even if they may seem identical, are subtly different, and even the compiler might get lost when choosing the right function to call. Listing all the possible cases would be a little too long for this answer, but you might want to check Herb Sutter GoTW #49 on the subject.
Oh, it'll compile. It just won't be a template function. You'll have a regular non-template function instead of a template specialization.
It's safe, and actually likely what you want as well. The Visitor pattern is normally implemented by overloading. Specializing function templates isn't really a good idea anyway.
What you did is not template serialization, but function overloading. It is safe.
P.S. It's difficult to say whether it's correct or not, without knowing what you're trying to achieve. Keep in mind that no matter is it template or overloaded function, your operator will be chosen in compile time. If you need to run-time dispatch, you need polymorphism, not overloading. Well, you probably know it anyway; just in case.
You have
void operator()(bool b) that is non
templated function
template< typename T > void
operator()(T t) which is a separate
base template that overloads the
above
You could have a full specialization of the second one as in template<> void operator(int i) which would only be considered when void operator()(bool b) did not match.
The specialization of base template is used to select which of the base template methods to call. However in your case you have a non-templated method that will get considered first.
The article Why Not Specialize Function Templates? gives quite good explanation of how the method is selected.
In sumary:
Non template functions are
considered first (this is your plain
operator()(bool) above)
Function base templates get checked
second (this is your templated
function), the most specialized base-template is selected and then if it has specialization for the exact types that specialization is used otherwise the base template is used with 'the correct' types (see explanation in the article)
Example:
#include <iostream>
using namespace std;
struct doh
{
void operator()(bool b)
{
cout << "operator()(bool b)" << endl;
}
template< typename T > void operator()(T t)
{
cout << "template <typename T> void operator()(T t)" << endl;
}
};
// note can't specialize inline, have to declare outside of the class body
template<> void doh::operator()<>(int i)
{
cout << "template <> void operator()<>(int i)" << endl;
}
template<> void doh::operator()<>(bool b)
{
cout << "template <> void operator()<>(bool b)" << endl;
}
int main()
{
doh d;
int i;
bool b;
d(b);
d(i);
}
You get calls to:
operator()(bool b) <-- first non template method that matches
template <> void operator()(int i) <-- the most specialized specialization of templated function is called