0

I have the following template class declaration:

template<void f(int)>
class A{
public:
    A(){
        struct sigaction sigact;
        ...
        if(sigact.sa_handler != f){
            ...
        }
    };
}

Can you tell me what this type of template is called? what is benefit of this template? This class is declared to install signal handler which is passed as f(int). Whenever we create an instance of this class, there is signal handler to be installed. I understand function templates and class templates. what is this template? I dont know why and what is benefit in this way?

Lei
  • 51
  • 6
  • 1
    Hi! You still didn't mark an answer to [your other question](http://stackoverflow.com/questions/23397459/what-does-the-following-declarations-mean), don't forget to do that! You apparently omitted the "juicy" parts of your template, and can you elaborate a little bit more on what you want to know? – Massa May 07 '14 at 14:43
  • @staticx There's no function pointer. It's just the function *type*. And the `int` doesn't have to be passed by reference, what makes you say that? – David G May 07 '14 at 14:48
  • @staticx non-type template arguments can be of one of the following types: integral type, enumeration, pointer to object or to function, lvalue reference to object or to function, pointer to member object or to member function, std::nullptr_t (since C++11)... – Massa May 07 '14 at 14:54
  • @0x499602D2: If you are referring to the template paramter `f`, I'm pretty sure it's a pointer. This will compile with the OP's code: `(*f)(1)`, for example. – kec May 07 '14 at 14:56
  • @kec That's because the expression `f` decays into a pointer, so a dereference operation is allowed there. The signature in the template parameters is the type of the function, which is **not** a pointer. `void (*f)(int)` would be a pointer. – David G May 07 '14 at 14:58
  • @0x499602D2: Okay, you are right that it's not a pointer, because you can't assign to it. But it's also not a type. A type has no value, for example. If it were a *type*, then you could do this: `f foo;`, which you can't. However, if you write: `using ft = void (int);`, then you *can* write: `ft foo;`, which declares `foo` to be a function, and is exactly equivalent to declaring `void foo(int);` So I would say that `f` is actually the address of a function, while `ft` is a type. – kec May 07 '14 at 15:05
  • @Massa, thx for reminding me of that. I am still new to here, so how can I mark an answer to that question? – Lei May 07 '14 at 15:09
  • @kec You're right about it not being a type, but `f` is not the address of the function (meaning a pointer thereto), it is the function itself (or maybe a copy thereof, I'm not sure). `void(int)` is a type; `void f(int)` or `void (f)(int)` is the declaration of a function (not a pointer or reference thereto). – David G May 07 '14 at 15:11
  • @0x499602D2: See this: http://ideone.com/VwISBR. I'm not sure which compiler they use, but I tried it on both clang++ and g++. It probably won't work on VS. – kec May 07 '14 at 15:16
  • @Lei Click the checkmark next to the answer that you wish to accept as your best answer. – David G May 07 '14 at 15:16
  • @Lei, it should appear a hollow tick mark (✔) below the upvote/downvote arrows and score counter, to the left of each answer. You just click on it and it becomes green, indicating that answer as the "correct" one for your question. – Massa May 07 '14 at 15:19
  • @0x499602D2: Just out of curiosity, here's another version that prints the `sizeof` of the template parameter: http://ideone.com/xhcxo3. – kec May 07 '14 at 15:24
  • @kec As I said before: `foo` decays into a pointer. `void f(int)` becomes `void (*f)(int)` similar to arrays. – David G May 07 '14 at 15:26
  • @0x499602D2: I'm not sure if I can give a really good answer, a true language lawyer will have to step in, except that there's a subtle distinction between the address of a function, a function, and the type of a function. BTW, at the object code level the `size` field for a function actually has the number of bytes taken up by the machine instructions. If you use Linux, you can get that with `nm -S`. – kec May 07 '14 at 15:29
  • @0x499602D2: But you can't apply `sizeof` to `foo`, while you can apply it to `f`. So there is still a difference. It's similar to how the `sizeof` an array is not the size of a pointer, even though arrays also decay into pointers. – kec May 07 '14 at 15:30
  • @kec You're kind of agreeing with my point: you can't apply `sizeof` to `foo` because `foo` is a function. `f` on the other hand already decayed into a pointer which gives `4` on a 32-bit system for pointer types. – David G May 07 '14 at 15:33

2 Answers2

2

Templates are parametrized types. In the case you brought, the name A refers to a family of types, one for each function of the form void f(int) that you pass to it. So, given the following declarations:

void print_int(int x);
void close_file(int x);
void handle_signal(int x);

A<print_int> p;
A<close_file> c;
A<handle_signal> s;

the variables p, c, and s have different (but related) types and the if block you highlighted above will only be entered if the function used to instantiate the template is NOT the same pointed-to by sigact.sa_handler.

Massa
  • 8,647
  • 2
  • 25
  • 26
0

It's a mechanism to make the class call different functions depending on how it's created. If you create the class with a function that returns true, your class will behave different as it you passed it a function that returns struct of type sigaction.

How you use that flexibility is an even bigger question, and depends on both your creativity and your requirements. In your example, you're specifying that the function you pass will return void, which... might not be ideal in the context you're using it since you're using it to compare to something else. Remember, though, that templates allow this kind of stuff.

This might as well be part of an even subject: Policy-based design.

Think about polymorphism. With that class, you can pass any kind of function as a parameter, effectively making C++ as close to a functional language as it can get, by making functions first class citizens (which means you can pass them as arguments to other functions directly, without function pointers or delegates, and without relying on lambdas).

The whole 'strategy' design pattern follows this same approach. On the original book, an example is hinted to use templates instead of inheritance-based polymorphism, which results in a cleaner and faster approach, loosing some flexibility (the downside of the templates is that you need to know how you're gonna use classes before runtime).

Hope this clears it up a bit, try reading the links, it will be very illustrative! =)

Community
  • 1
  • 1
ArthurChamz
  • 2,039
  • 14
  • 25
  • Actually, the template as declared does not allow changing the signature of the function; only the function itself. Thus... your answer is informative but appears to be only tangential. – Matthieu M. May 07 '14 at 15:16
  • I have been thinking about this. I think I did get sidetracked, but as it stands, I might as well just leave it like that. – ArthurChamz May 07 '14 at 15:20