Can't have static and instance member functions with same name?

Mar 16, 2012 at 6:08pm
Why can't you have a static and an instance member function with the same signature?
1
2
3
4
5
class A
{
    void DoThing(){}
    static void DoThing(){}
};
1
2
3
4
A a;
a.DoThing(); //can only possibly call the instance member function
A::DoThing(); //can only possibly call the static member function
//Same for pointer-to-member vs function pointer to static func... 
It seems perfectly logical, because there is no ambiguity in any cases I can think of. Why does the code give an error?
Last edited on Mar 16, 2012 at 6:09pm
Mar 16, 2012 at 6:18pm
because the static variable or function is not attached to the object of the class , but class itself . so when you call it by the object of the class it will be ambiguous .
Mar 16, 2012 at 6:20pm
I'm not sure why. If you write &A::DoThing; it can't know which one you mean, but you will have that problem also when there is more than one function with the same name but different signatures.

You can also not have data member with the same name as any member function. I guess they just want to minimize ambiguity.
Mar 16, 2012 at 6:37pm
a.DoThing(); //can only possibly call the instance member function

I don't think that's true. That's a perfectly legal way to call static members as well.

Also...

1
2
3
4
5
6
7
8
9
10
void A::Foo()  // member function of A
{
  DoThing();  // <- does this call the static or nonstatic version?
  A::DoThing();  // <- what about this?
}

int main()
{
  somefuncptrtype = &A::Foo;  // does this get a pointer to the static or nonstatic?
}


Of course, all of the above are rhetorical questions, as there is no right answer. These ambiguities are likely why this is not allowed.


EDIT:

although I wonder how the function pointer issue is solved for overloaded functions.... interesting....
Last edited on Mar 16, 2012 at 6:38pm
Mar 16, 2012 at 7:15pm
Disch wrote:
That's a perfectly legal way to call static members as well.
Now, see, this is one the the things that I think both Java and C++ got wrong. It makes no sense to access a static member from an instance, especially since it has no polymorphic behavior and is equivalent to using the class' name instead. I don't understand why this would work, but you're right, I just tested and it works oddly enough in C++. Guess I need an explanation on this too...

Edit: also, check this out:
1
2
3
4
void DoThing(){}
void DoThing(int){}
typedef void (*Sig)();
Sig s (&DoThing);
compiles just fine - so why can't it be the same with member function pointers vs regular function pointers?
Last edited on Mar 16, 2012 at 7:23pm
Mar 16, 2012 at 8:11pm
Why can't you have a static and an instance member function with the same signature?


The static storage class specifier doesn't "change" the signature of the function, therefore, the signatures are identical as far as the compiler is concerned and is ambiguous.
Mar 16, 2012 at 8:14pm
LB wrote:
It makes no sense to access a static member from an instance


It can help with writing generic/templated code.

LB wrote:
compiles just fine - so why can't it be the same with member function pointers vs regular function pointers?


I'm a little fuzzy on how it can get that right. I don't have a good answer for you here.

clanmjc wrote:
The static storage class specifier doesn't "change" the signature of the function,


Yes it does. Non-static functions take a hidden parameter to act as a "this" pointer within the function. Static functions have no such parameter.
Last edited on Mar 16, 2012 at 8:14pm
Mar 16, 2012 at 8:22pm
Disch wrote:
It can help with writing generic/templated code.
Can I seen an example? I keep thinking of template<typename T> and using T::Something(), but I'm probably skipping over an important situation where that isn't applicable.

EDIT: And, please, don't say 'macros', unless that is the absolute only case.
Last edited on Mar 16, 2012 at 8:23pm
Mar 16, 2012 at 8:27pm
Disch wrote:
Yes it does. Non-static functions take a hidden parameter to act as a "this" pointer within the function. Static functions have no such parameter.


Yes the Non-static function has the implicit 'this' pointer, but it is not a formal argument and only formal arguments are used in function match criteria.
Last edited on Mar 16, 2012 at 8:43pm
Mar 16, 2012 at 8:36pm
LB wrote:
Can I seen an example?


1
2
auto foo = SomeFunction();
foo.StaticMember();


EDIT:

Also the T::StaticMember approach doesn't work if the static member is in a parent class of T:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Parent
{
public:
  static void Func(){}
};

class Child : public Parent {};

template<typaname T>
void Foo(T v)
{
  v.Func();  // OK
  T::Func();  // fails, T=Child and Func is not a member of Child
}

int main()
{
  Child c;
  Foo(c);
}


clanmjc wrote:
Yes the Non-static function has the implicit 'this' pointer, but it is not a formal arguments and only formal arguments are used in function match criteria.


Ah, okay, I was misunderstanding and thought you were talking about something else. Nevermind.

Last edited on Mar 16, 2012 at 8:43pm
Mar 16, 2012 at 8:47pm
There is a simple rule in overloading a class methods or a simple function.

You cant overload a function or class method by it's return value or by declaring it as inline or just a normal function or by declaring it as static and none static function. That cant be done. A function cant be overloaded in this way.

What you are doing here is nothing else , but just overloading your DoThing by declaring it once as static and than as none static( that can be done only if there is a differences between the parameters which are taken by the functions). The compiler can not make any differences between your two methods.


may be some thing like
1
2
3
4
5
6
class A
{
    void DoThing();
    static void DoThing(int i );

};
Last edited on Mar 16, 2012 at 8:50pm
Mar 16, 2012 at 9:34pm
@Disch if we're talking C++11, would not decltype(foo)::StaticMember() be suitable? I know it doesn't work, just seems like it should.

Anyway, thanks for all the answers - I've definitely learned some interesting stuff this thread.
Mar 16, 2012 at 9:40pm
It makes no sense to access a static member from an instance

This is a critical piece when it comes to memory management classes, think shared pointers and state machines.

I too learned some interesting things from this thread.
Last edited on Mar 16, 2012 at 9:41pm
Mar 17, 2012 at 5:38am
This is kind of useless but,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class
{
public:

	static void do_something() ;
} object ;


int main()
{
        // do_something() ;

	object.do_something();
}


You can't access a static member of an anonymous class without an instance of the class.

Last edited on Mar 17, 2012 at 5:38am
Mar 17, 2012 at 5:44am
I didn't even know anonymous classes could have static members :o
Mar 17, 2012 at 3:56pm
> The static storage class specifier doesn't "change" the signature of the function

Of course, it does. A static member function of a class has the same signature as a free function.

> Yes the Non-static function has the implicit 'this' pointer, but it is not a formal argument
> and only formal arguments are used in function match criteria.

This is absurd. How is overloading based on the cv-qualifiers allowed?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
struct A
{
    int non_static_mfun_one( int i ) const { return non_static_mvar_one + i ; }

    // these are valid overloads; the parametrs are of different types
    // the cv-qualifiers affect the type of the this pointer
    // and therefore also affect the type of the member function
    int non_static_mfun_two( int i ) { return i += non_static_mvar_two ; }
    int non_static_mfun_two( int i ) const { return non_static_mvar_two + i ; }
    int non_static_mfun_two( int i ) volatile { return i += non_static_mvar_two ; }

    int non_static_mvar_one = 1 ;
    int non_static_mvar_two = 2 ;

    static int static_mfun_one( int i ) { return static_mvar_one + i ; }
    static int static_mfun_two( int i ) { return static_mvar_two + i ; }

    static int static_mvar_one ;
    static int static_mvar_two ;
};

int A::static_mvar_one = 10 ;
int A::static_mvar_two = 20 ;

int free_function( int i ) { return i + 6 ; }
int free_variable = 100 ;

int main()
{
     int A::*pointer_to_member_var = nullptr ;
     int* pointer_to_free_var = nullptr ;
     int (A::*pointer_to_member_fun)(int) const = nullptr ;
     int (*pointer_to_free_fun)(int) = nullptr ;

     pointer_to_member_var = &A::non_static_mvar_one ; // ok
     pointer_to_member_var = &A::non_static_mvar_two ; // ok
     // pointer_to_member_var = &A::static_mvar_one ; // *** error ***
     // pointer_to_member_var = &free_variable ; // *** error ***

    pointer_to_free_var = &A::static_mvar_one ; // ok
    pointer_to_free_var = &A::static_mvar_two ; // ok
    pointer_to_free_var = &free_variable ; // ok
    //pointer_to_free_var = &A::non_static_mvar_one ; // *** error ***

     pointer_to_member_fun = &A::non_static_mfun_one ; // ok
     pointer_to_member_fun = &A::non_static_mfun_two ; // ok
     //pointer_to_member_fun = &A::static_mfun_one ; // *** error ***
     //pointer_to_member_fun = &free_function ; // *** error ***

     pointer_to_free_fun = &A::static_mfun_one ; // ok
     pointer_to_free_fun = &free_function ; // ok
     //pointer_to_free_fun = &A::non_static_mfun_one ; // *** error ***

     int (A::*pointer_to_volatile_member_fun)(int) volatile = nullptr ;
     pointer_to_volatile_member_fun = &A::non_static_mfun_two ; // ok
     //pointer_to_volatile_member_fun = &A::non_static_mfun_one ; // *** error ***
     // the parameter types are different (for the this pointer)
}




> Also the T::StaticMember approach doesn't work if the static member is in a parent class of T:
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Parent
{
public:
  static void Func(){}
};

class Child : public Parent {};

template<typaname T>
void Foo(T v)
{
  v.Func();  // OK
  T::Func();  // fails, T=Child and Func is not a member of Child
}

int main()
{
  Child c;
  Foo(c);
}

Line 13 is OK too; Func is looked up during the second phase of the two-phase name look up.

This would fail though; dependant names are not looked up during the first phase.
1
2
3
4
5
6
7
8
9
10
template< typename T > struct base { static void foo() {} };

template< typename T > struct derived {} ;

int main()
{
     derived<int> object ;
     derived<int>::foo() ; // *** error *** 'derived<int>' has no member named 'foo'
     object.foo() ; // *** error *** 'derived<int>' has no member named 'foo'
}

Topic archived. No new replies allowed.