Reputation: 4283
I've been experimenting with function types in C++. Note that I don't mean pointer-to-function types like:
typedef void (*voidFuncPtr)();
but the more exotic:
typedef void (voidFunc)();
I didn't expect the following code to compile, but surprisingly it did:
template<voidFunc func>
class funcClass
{
public:
void call() { func(); };
};
void func()
{ }
void Test()
{
funcClass<func> foobar;
foobar.call();
}
however, if I try adding the following to funcClass:
voidFuncPtr get() { return &func; }
I get the error Address expression must be an lvalue or a function designator
My first question here is: what kind of black magic is the compiler using to pretend that a func type is something it can actually pass around an instance of? Is it just treating it like a reference? Second question is: if it can even be called, why can't the address of it be taken? Also, what are these non-pointer-to function types called? I only discovered them because of boost::function, and have never been able to find any documentation about them.
Upvotes: 4
Views: 199
Reputation: 75130
§14.1.4 of the Standard says:
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, [this is what yours is]
— lvalue reference to object or lvalue reference to function,
— pointer to member,
— std::nullptr_t.
And §14.1.6 says
A non-type non-reference template-parameter is a prvalue. It shall not be assigned to or in any other way have its value changed. A non-type non-reference template-parameter cannot have its address taken. When a non-type non-reference template-parameter is used as an initializer for a reference, a temporary is always used.
So that explains the two behaviours you are seeing.
Note that func
is the same as &func
(§14.3.2.1):
[A non-type template parameter can be] a constant expression (5.19) that designates the address of an object with static storage duration and external or internal linkage or a function with external or internal linkage, including function templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as & id-expression, except that the & may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference; or...
So it's just a function pointer.
Upvotes: 4
Reputation: 153840
Given that the code compiles without the address-of operator and pointers (including to functions and member functions) are valid template arguments, it seems the compiler considers voidFunc
to be a function pointer type, i.e., the decayed version of the type. The rules for this didn't change between C++ 2003 and C++ 2011.
Upvotes: 2