Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

passing function as parameter to template method of template class

Tags:

c++

c++11

The following code looks legitimate but doesn't compile

void f() {}

template<bool>
struct call_any
{
    template<typename F>
    static void call(F f) {}
};

template<bool B>
void call_f()
{
    call_any<true>::call<void (&)()>(f);  // OK
    call_any<false>::call<void (&)()>(f); // OK
    call_any<B>::call<void()>(f);         // OK
    call_any<B>::call<void (&)()>(f); // expected primary-expression before '>'
}

Why there is an error and what does it mean?

like image 433
a.lasram Avatar asked Jul 05 '13 02:07

a.lasram


People also ask

Can we pass Nontype parameters to templates?

Template classes and functions can make use of another kind of template parameter known as a non-type parameter. A template non-type parameter is a template parameter where the type of the parameter is predefined and is substituted for a constexpr value passed in as an argument.

Can a template be a template parameter?

A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)

Which of the following can be passed to a function template as an argument?

Explanation: A template parameter is a special kind of parameter that can be used to pass a type as argument.

What is the difference between template class and template function?

For normal code, you would use a class template when you want to create a class that is parameterised by a type, and a function template when you want to create a function that can operate on many different types.


1 Answers

When you are dealing with types that are dependent on the template parameters within a template, the compiler doesn't know what kinds of things the members of that type are. Unless you specify otherwise, it assumes that the members are not types and not templates. Because of this, it is trying to treat < as a less-than operator, but it becomes impossible to parse the expression that way by the time it reaches the >.

To get rid of the error you should use this instead:

call_any<B>::template call<void (&)()>(f);

This tells the compiler explicitly that call is a template, so it should treat the < as the beginning of the template parameters and not a regular less-than operator.

This should use template as well:

call_any<B>::call<void()>(f); 

The only reason you don't see the error on this line is that there is a way to parse it as a non-template:

(call_any<B>::call < void() ) > (f);

Although odd, it is syntatically valid, so the compiler gets past that line, and the first error you see is the one you mention. However, without the template keyword, you would eventually get an error once call_f was actually instantiated (probably -- there are weird ways it could work).

The first two examples are okay without using the template keyword. Since the type isn't dependent on the template parameters, it can be determined that call is a template while call_f is being parsed.

You might ask: "Why can't the compiler figure out it is a template? I've defined it as a template in the code right above!". The issue is specialization. You could specialize the template and do something completely different than what the primary template specifies:

template<>
struct call_any<false>
{
    static const int call = 5;
};

This specialization could occur even after call_f is defined, so the compiler can't rely on what the primary template for call_any says when it is parsing call_f.

like image 160
Vaughn Cato Avatar answered Sep 28 '22 01:09

Vaughn Cato