Function signature-like expressions as C++ template arguments
With regards to your first question - about the type int(char, float)
- this is a valid C++ type and is the type of a function that takes in a char
and a float
and returns an int
. Note that this is the type of the actual function, not a function pointer, which would be an int (*) (char, float)
. The actual type of any function is this unusual type. For example, the type of
void DoSomething() {
/* ... */
}
is void ()
.
The reason that this doesn't come up much during routine programming is that in most circumstances you can't declare variables of this type. For example, this code is illegal:
void MyFunction() {
void function() = DoSomething; // Error!
}
However, one case where you do actually see function types used is for passing function pointers around:
void MyFunction(void FunctionArgument()) {
/* ... */
}
It's more common to see this sort of function written to take in a function pointer, but it's perfectly fine to take in the function itself. It gets casted behind-the-scenes.
As for your second question, why it's illegal to have the same template written with different numbers of arguments, I don't know the exactly wording in the spec that prohibits it, but it has something to do with the fact that once you've declared a class template, you can't change the number of arguments to it. However, you can provide a partial specialization over that template that has a different number of arguments, provided of course that the partial specialization only specializes over the original number of arguments. For example:
template <typename T> class Function;
template <typename Arg, typename Ret> class Function<Ret (Arg)> {
/* ... */
};
Here, Function
always takes one parameter. The template specialization takes in two arguments, but the specialization is still only over one type (specifically, Ret (Arg)
).
int* int_pointer; // int_pointer has type "int*"
int& int_reference; // int_reference has type "int&"
int int_value; // int_value has type "int"
void (*function_pointer)(int, int); // function_pointer has type
// "void (*)(int, int)"
void (&function_reference)(int, int); // function_reference has type
// "void (&)(int ,int)"
void function(int, int); // function has type
// "void(int, int)"
template<>
struct Object1<void(int, int)>
{
void m_member1(int, int); // wait, what?? not a value you can initialize.
};