Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Why can't member functions be called statically?

44 views
Skip to first unread message

Rick C. Hodgin

unread,
Mar 13, 2017, 9:53:44 PM3/13/17
to
What is the underlying reason why C++ prevents non-static member
functions from being called statically?

If they didn't reference member variables or things which require
a "this," or if they did so only under the scrutiny of discriminating
control flow logic, why would it be an issue? Why should it be
prevented?

Thank you,
Rick C. Hodgin

Alf P. Steinbach

unread,
Mar 13, 2017, 10:50:02 PM3/13/17
to
It's just the simplest rules.

There is nothing to be gained by adding rules that would allow a
non-this-accessing non-static member function to be called statically,
because that's the case of a member function that can be called both
statically and on an object, which is already covered by static member
functions: that's what should be used for this case.

E.g.


#include <iostream>
using namespace std;

struct S
{
static void foo() {}
};

auto main()
-> int
{
S::foo(); // static call
S{}.foo(); // call on an object, also OK.
}


Cheers & hth.,

- Alf

Rick C. Hodgin

unread,
Mar 13, 2017, 11:21:58 PM3/13/17
to
On Monday, March 13, 2017 at 10:50:02 PM UTC-4, Alf P. Steinbach wrote:
> There is nothing to be gained by adding rules

It would be removing constraints, not adding rules.

> that would allow a
> non-this-accessing non-static member function to be called statically,
> because that's the case of a member function that can be called both
> statically and on an object, which is already covered by static member
> functions: that's what should be used for this case.

class xyz
{
public:
xyz();
~xyz();

int abc(int a, int b, int c);

private:
static int k;
};

If I were to call xyz::abc(1, 0, 0), k would be in scope because
it's also static. But in addition, why couldn't an extension be
added to recognize I'm calling it from a static context, and then
possibly modify the dynamics by some runtime lookup?

int xyz::abc(int a, int b, int c)
{
// If called in a static context, use this block to perform
// a contextual lookup to derive the this member
static {
this = xyz::perform_some_lookup(a);
if (!this)
return -1; // No suitable context was found
}

// No longer static, runs with a proper context from here down

Rick C. Hodgin

unread,
Mar 13, 2017, 11:37:30 PM3/13/17
to
On Monday, March 13, 2017 at 11:21:58 PM UTC-4, Rick C. Hodgin wrote:
> int xyz::abc(int a, int b, int c)
> {
> // If called in a static context, use this block to perform
> // a contextual lookup to derive the this member
> static {
> this = xyz::perform_some_lookup(a);
> if (!this)
> return -1; // No suitable context was found
> }
>
> // No longer static, runs with a proper context from here down
> }

Such a context would be useful in an OS message handler, for example,
where messages are sent to a single function, but are intended for a
specific target, and the target isn't known until a lookup is performed
to identify the associated object from some list of things that the OS
could be responding to.

For Windows it could by the hwnd member that's used to identify the
particular window instance that's being updated, along with the class
related to processing that window.

In that case, the code could be modified:

LRESULT CALLBACK xyz::wndProc(HWND hwnd, UINT m, WPARAM w, LPARAM l)
{
static {
this = xyz::find_related_window(hwnd);
if (!this)
return DefWindowProc(hwnd, m, w, l);
}

// Now we have the correct class instance associated with this
// static callback from the OS. All members will be dynamically
// referenceable now.

Rick C. Hodgin

unread,
Mar 13, 2017, 11:44:19 PM3/13/17
to
On Monday, March 13, 2017 at 11:37:30 PM UTC-4, Rick C. Hodgin wrote:
> Such a context would be useful in an OS message handler, for example,
> where messages are sent to a single function, but are intended for a
> specific target, and the target isn't known until a lookup is performed
> to identify the associated object from some list of things that the OS
> could be responding to.
>
> For Windows it could by the hwnd member that's used to identify the
> particular window instance that's being updated, along with the class
> related to processing that window.
>
> In that case, the code could be modified:
>
> LRESULT CALLBACK xyz::wndProc(HWND hwnd, UINT m, WPARAM w, LPARAM l)
> {
> static {
> this = xyz::find_related_window(hwnd);
> if (!this)
> return DefWindowProc(hwnd, m, w, l);
> }
>
> // Now we have the correct class instance associated with this
> // static callback from the OS. All members will be dynamically
> // referenceable now.
> }

In addition, using a passed parameter to call a static reference as
for spawning a thread:

CreateThread(NULL, 0, &threadHandler, params, NULL, &params.threadId);

Dispatches to:

DWORD WINAPI xyz::threadHandler(LPVOID params)
{
// Re-establish our local class instance
static {
this = ((SParams*)params)->xyz;
}

// Now, the statically called member function is back in
// local scope, despite its necessary routing through the
// OS API for thread spawning and dispatching.
}

And there are many other such uses, where the dynamic instance can
be known, but it's just not known at the time of dispatch because
it requires some kind of lookup, or a re-establishing from a passed
parameter.

Ian Collins

unread,
Mar 14, 2017, 12:07:58 AM3/14/17
to
Because there's no good reason not to make them static members?

How could the compiler tell if a non-inline member function behaved as
you describe?

If you really want to, you can lie to the compiler and do:

struct X
{
void f() {}
};

int main()
{
static_cast<X*>(nullptr)->f();
}

--
Ian

Jerry Stuckle

unread,
Mar 14, 2017, 10:09:18 AM3/14/17
to
"this", then why not declare them static?

As for control flow logic - that is run-time. The compiler cannot
predict the control flow logic would never let it occur.

--
==================
Remove the "x" from my email address
Jerry Stuckle
jstu...@attglobal.net
==================

Rick C. Hodgin

unread,
Mar 14, 2017, 11:06:55 AM3/14/17
to
On Monday, March 13, 2017 at 11:21:58 PM UTC-4, Rick C. Hodgin wrote:
> class xyz
> {
> public:
> xyz();
> ~xyz();
>
> int abc(int a, int b, int c);
>
> private:
> static int k;
> };
>
> If I were to call xyz::abc(1, 0, 0), k would be in scope because
> it's also static. But in addition, why couldn't an extension be
> added to recognize I'm calling it from a static context, and then
> possibly modify the dynamics by some runtime lookup?
>
> int xyz::abc(int a, int b, int c)
> {
> // If called in a static context, use this block to perform
> // a contextual lookup to derive the this member
> static {
> this = xyz::perform_some_lookup(a);
> if (!this)
> return -1; // No suitable context was found
> }
>
> // No longer static, runs with a proper context from here down
> }

Within this context, provided you weren't calling a virtual function,
this would be legal:

void myFunction(void)
{
xyz* x = NULL;

x->abc(5, 0, 0);
}

The symbol x would identify the class, which then called its known
static location in source code with itself as a parameter. If it's
NULL, then it would enter the static block and could be established
there.

The only reason you'd need x is for the members. Or, in the case
of a virtual function, for the explicit vtable lookup. But it's
even arguable in those cases that you wouldn't need it, because
you could use the type to reference a global virtual member
function address table, which then still references the correct
target with a NULL parameter, allowing the static {..} block to
be entered, where the correct this context is established.

The compiler would not be aware of potential run-time errors, but
the developer would. So long as all of the discrimination was
handled properly, it would not be in error in any case. And where
it was, it would signal a runtime fault (in C++, or an inquiry in
CAlive).

-----
I don't see any issues with this change in design (in terms of
working correct, though I realize it would change established
practices and protocols in C++ software development).

Do you?

Alf P. Steinbach

unread,
Mar 14, 2017, 11:10:24 AM3/14/17
to
On 14-Mar-17 4:06 PM, Rick C. Hodgin wrote:
>>
[snip]
>> int xyz::abc(int a, int b, int c)
>> {
>> // If called in a static context, use this block to perform
>> // a contextual lookup to derive the this member
>> static {
>> this = xyz::perform_some_lookup(a);
>> if (!this)
>> return -1; // No suitable context was found
>> }
>>
>> // No longer static, runs with a proper context from here down
>> }
>
[snip]
> I don't see any issues with this change in design (in terms of
> working correct, though I realize it would change established
> practices and protocols in C++ software development).
>
> Do you?

What are some examples where this scheme has some advantage?


Cheers!

- Alf


Rick C. Hodgin

unread,
Mar 14, 2017, 11:42:31 AM3/14/17
to
I gave two above (callbacks from OS services which derive the
specific instance based on information passed as parameters in
the callback).

I see the straight-forward redefinition of the this member to be
flexible, assignable. I see the static {..} block as being a very
positive feature (as CAlive also adds angel classes which are
short-duration classes which instantiate and de-instantiate auto-
matically in context, and could be used to support dynamic features
on static calls when no instance could be identified).

I see the ability to make dynamic and static functions essentially
the same for all internal function calls, more closely mimicking
what is actually seen in the physical ABI.

It makes everything more solid in the system, which reflects more
accurately what it really is in terms of the underlying mechanics,
(classes are logical constructs relating to physical implementations),
but it also makes it more flexible because things like an on-the-fly
change of the this member would be possible:

xyz* p1 = new xyz(15); // Create with a value of 15
xyz* p2 = new xyz(10); // Create with a value of 10

p1->some_function(p2);

void xyz::some_function(xyz* p2)
{
if (p2->value < value)
this = p2;

// Now, the entire reference to this instance is the min
// of the two parameters, without having to assign to a
// separate function pointer and then being required to
// use that on every reference.
}

-----
The only issue I see would be in legacy code interfaces. The missing
parameter on static callbacks from pre-existing functions that are
not aware they're calling a class member function statically, those
would need fixups.

In those legacy cases, the compiler could auto-create a marshalling
function which handles adding the extra parameter until the API
designer can create a version which auto-adds the extra NULL
parameter for the class member function static callback.

Add the keyword "static":

CreateThread(..., static &threadHandler, ...);
^^^^^^
In those legacy cases, the compiler would then auto-inject the marshal
function which is the OS API callback target, which then directs to
the correct function with the expected parameter.

In future releases, the OS API would be updated and we'd use the new
function static class callback function, which is called directly:

CreateThreadSC(..., &threadHandler, ...);

The new function would acknowledge its callback is a static class,
and would auto-inject the extra NULL parameter for the class instance
of the static callback. This would then signal code to enter the
static {..} block to derive the runtime context.

Mr Flibble

unread,
Mar 14, 2017, 1:01:10 PM3/14/17
to
I thought there was a general consensus within the group to not reply to
the fucktard Hodgin's C++ related posts until he promises to stop
spamming the group with his bullshit religious posts?

/Flibble


Rick C. Hodgin

unread,
Mar 14, 2017, 1:36:18 PM3/14/17
to
On Tuesday, March 14, 2017 at 1:01:10 PM UTC-4, Mr Flibble wrote:
> I thought there was a general consensus within the group to not reply
> to the .. Hodgin's C++ related posts until he promises to stop
> spamming the group with his .. religious posts?

Not everyone's so petty and childish, Leigh. Which of these "honorable
men" would you be most like?

Star Trek TNG -- Worf receiving discommendation
https://www.youtube.com/watch?v=5c2etjMl3WM
0 new messages