On 26-Apr-17 5:54 PM,
porp...@gmail.com wrote:
>
> When I create an object of type boost::function I do it e.g. as follows:
> boost::function<int(int,int)> boostFun2;
>
> Why I cannot create an object of type int(int,int) ? e.g.
> int(int,int) myFun;
Shortest possible explanation: there's no syntax for that.
But that short explanation ignores why there's no such syntax, so let's
delve into that.
Some computers (mostly digital signal processors) have Harvard
architecture where machine code is kept in one memory, and data in
another. Or at least it works as if that were the case. So a given
address can mean one thing when used as a code memory address, and
another when used as a data memory -- ordinary memory -- address.
C++ and most conventional languages only support dealing directly with
contents of data memory. When you declare a variable it's an abstraction
of a piece of data memory. When you change the value of an object it's
change of data memory contents.
The language doesn't support inspecting or changing contents of code
memory except that on most machines you can get at it via data memory,
because on most machines, with von Neumann architecture, those memories
and address spaces are in fact one and the same, the unification of code
and data which Johann von Neumann (undeservedly) got famous for.
However, C++ supports dealing with code memory addresses as /function
pointers/. I.e. a data memory object that contains the start address of
a function's machine code in code memory. You can't portably inspect the
machine code at such an address, but you can copy these pointers around,
in data memory, and you can invoke a function pointed to.
Here's an example:
#include <iostream>
using namespace std;
using My_func = auto(int, int) -> int;
void do_something_with( My_func* const f )
{
auto const addr = reinterpret_cast<void const*>( f );
cout << "It's function address " << addr << ".\n";
cout << "f(2, 3) = " << f(2, 3) << "\n";
}
auto foo( int a, int b ) -> int { return a*b; }
auto main()
-> int
{ do_something_with( &foo ); }
The cast to `void*` here, for the purpose of outputting the address, is
not necessarily supported by any particular compiler. With C++11 and
later is allowed to optionally support this, and most compilers do. But
a compiler for a Harvard architecture digital signal processor may not
necessarily support it, so even in practice this is not entirely
portably code.
A possibly more portable alternative is to use a cast to `uintptr_t`,
but that's less convenient.
Anyway, C++ has special support for function pointers. For example, as
shown above, instead of writing `(*f)(2, 3)` you can write just `f(2,
3)`, as if the pointer were directly the name of a function.
Also, instead of `My_func* f` (no `const`) you can write just `My_func
f` as formal argument type, and because it is a formal argument type you
get an automatic DECAY to pointer type, not just of the argument name
used in an expression, but of the actual type of the argument. Which
baffles many a novice. There's a corresponding decay of array to pointer
to item.
For both pointers and arrays there are also such decays for function and
array names used in expressions, i.e. decays of expression value type.
E.g. instead of `&foo` above, to get the address of `foo`, I could have
written just `foo`. Happily these value type decays do not occur when
you bind a function or array to a reference.
Also, if you write
My_func f;
at namespace scope, then (as opposed to the literally same declaration
as a formal argument) there's no type decay, and the result is not a
data memory object but a declaration of a function in code memory.
A definition of the function can't have that form -- there's no syntax
for that -- but it's possible to just declare a function this way. I
do not know what the rationale is. I've never needed it.
Cheers & hth.,
- Alf