25

I have defined class template named CallBackAtInit which only purpose is to call a function at its initialization (constructor). The function is specified in template parameters. The problem is that templates does not accept std::function as parameters; but they accept function pointers. Why?

Here is my code:

#include <iostream>
#include <functional>

/* Does not work:*/     template <typename return_type, typename arg_type, std::function<return_type(arg_type)> call_back>
/* Work fine: *///      template <typename return_type, typename arg_type, return_type(*call_back)(arg_type)>

class CallBackAtInit {
public:
    CallBackAtInit(arg_type arg)
    {
        call_back(arg);
    };
};

void printInt(int i);

class HoldInt : private CallBackAtInit<void, int, printInt> {
public:
    HoldInt(int integer)
    : CallBackAtInit(integer)
    {}
    // ...
};

int main(int argc, char** argv)
{
    HoldInt hi(10);
    return 0;
}

void printInt(int i)
{
    std::cout << i << std::endl;
}
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Leonardo Raele
  • 2,400
  • 2
  • 28
  • 32
  • 1
    Can you post your compile error ? – Jean-Marie Comets Dec 01 '12 at 16:46
  • 1
    @Jean-Marie Comes Off course. main.cpp:4:115: error: ‘struct std::function’ is not a valid type for a template constant parameter – Leonardo Raele Dec 01 '12 at 19:00
  • 1
    I think you should update your question title and / or body to make it clear you're referring to *non-type* parameters. A std::function is a valid template parameter, i.e. `>`, it is just not valid as a non-type parameter – j b Jan 18 '19 at 09:50

2 Answers2

14

The parameter for a template definition can be of four kinds:

  • parameter which can accept only type (or template type).
  • parameter which can accept only integral value.
  • parameter which can accept only pointer-to-member value.
  • std::nullptr_t (since C++11)

When you mention std::function in a template definition, then it falls neither of the above categories. The template cannot accept types, nor can it accept integral value, or pointer-to-member value.

When the parameter is function pointer type, then it can accept function-pointer (the address of a function matching the type) which is just an integral value. Note that address is always an integral value. So it falls into the second category, which is why it works.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 2
    -1, There are other allowed forms of non-type template parameter. Is a pointer to member an integral type? Is `nullptr_t` an integral type? Is a reference an integral type? – Jonathan Wakely Dec 01 '12 at 17:10
  • @JonathanWakely: Edited. The type *pointer-to-member* just skipped my mind. And `nullptr_t` didn't occur to me. – Nawaz Dec 01 '12 at 17:22
3

Because it's not allowed by the standard:

14.1 Template parameters

4 A non-type template-parameter shall have one of the following (optionally cv-qualified) types:

— integral or enumeration type,

— pointer to object or pointer to function,

— lvalue reference to object or lvalue reference to function,

— pointer to member,

— std::nullptr_t.

chill
  • 16,470
  • 2
  • 40
  • 44
  • 21
    +1 but it would be good to explain _why_ only those types are allowed. The reason is that those types have values that can be known at compile time, when templates are processed. A non-trivial type such as `std::function` doesn't have a known constant value at compile-time, neither does a type such as `std::string` – Jonathan Wakely Dec 01 '12 at 17:12
  • 8
    I cannot read this answer without downvoting it. The questioner *already knows* that it is invalid in C++. He says *"Why isn't std::function a valid template parameter while a function pointer is?"*. How is it helpful to tell him that it is not allowed? It's your luck that @JonathanWakely is more forgiving than me. – Johannes Schaub - litb Dec 02 '12 at 00:29
  • 2
    @JohannesSchaub-litb, well, in fact there are lot more types that can have values known at compile/link time to the last bit of the representation, like floats or any cartesian product of the types, already in the list, a.k.a. structs, which might include instances of `std::function` as well, so, strictly speaking, the answer to "why?" is "just because!". – chill Dec 02 '12 at 11:39
  • if you would have put that comment in your answer i would not have downvoted :-) – Johannes Schaub - litb Dec 02 '12 at 11:48
  • @JohannesSchaub-litb, hehe, anyway ... :) – chill Dec 02 '12 at 11:51