0

Here is an example of using pointer to member functions:

int main(){

     struct A {
        void Foo(){
            std::cout << "A::Foo()" << std::endl;
        }
    };

    void (A::*pFunc)() = &A::Foo;

    A a;
    (a.*pFunc)(); // works fine

    A a2();
    pFunc = &A::Foo;
    (a2.*pFunc)(); // This doesn't work?


    return 0;
}

Above if I declare an object of class A without () It works fine but if I declare it with it doesn't work?

I get this error:

Severity    Code    Description Project File    Line
Error   C2296   '.*': illegal, left operand has type 'main::A (__cdecl *)(void)'    ConsoleApplication3 c:\users\raindrop7\desktop\consoleapplication3\consoleapplication3\consoleapplication3.cpp  89
Raindrop7
  • 3,889
  • 3
  • 16
  • 27
  • Look up "most vexing parse". Using uniform initialization prevents this problem. – nwp Nov 09 '17 at 13:51
  • @nwp: Could you show how? – Raindrop7 Nov 09 '17 at 13:52
  • `A a2{};`. Always use `{}` when you intent to create an object and `()` when you intend to call a function. This has some issues with initializer lists being preferred to constructors, but that is an exception to the rule. – nwp Nov 09 '17 at 13:53
  • @nwp: Thank you that solves the problem. – Raindrop7 Nov 09 '17 at 13:54
  • @nwp do not give that advise, it is dangerous and leads to much worse problems – Slava Nov 09 '17 at 14:01
  • 1
    @Slava - Don't respond to one broad statement with another broad statement. For most user-defined types, it's perfectly fine and advisable. – StoryTeller - Unslander Monica Nov 09 '17 at 14:03
  • @Slava reaylly? –  Nov 09 '17 at 14:03
  • @StoryTeller yes that is the problem, most types. On one side you have compilation error which is easy to catch, on another hard to catch runtime issues. Good advise! – Slava Nov 09 '17 at 14:05
  • @manni66 yes really, imagine you typedef a type and later you change it to a type that has initializer list constructor override, good luck to catch that. – Slava Nov 09 '17 at 14:06
  • @Slava - Oh, yeah. It's such an easy error to catch and understand that this question was never asked before. Please. – StoryTeller - Unslander Monica Nov 09 '17 at 14:06
  • @StoryTeller compile error much easier to catch than runtime. – Slava Nov 09 '17 at 14:07
  • 2
    @Slava - Evidently not. You seem to forget that some templated code will happily accept a function pointer and compile. So now you have a run-time error just the same. And it's incredibly not obvious. There is no silver bullet. I'm with nwp, at least you know you have an object of the type, always, when you do uniform initialization. – StoryTeller - Unslander Monica Nov 09 '17 at 14:10
  • @StoryTeller it is next to impossible to hit your issue, issue with initializer list I hit by myself. A program when you use mix 2 styles looks ugly and unreadable. – Slava Nov 09 '17 at 14:13
  • @Slava - So because you hit it, everybody must hit it? *I* never hit it. But maybe I was overly cautious to begin with. – StoryTeller - Unslander Monica Nov 09 '17 at 14:13
  • @StoryTeller if you make it as a habbit you will hit it sooner or later, yes I am pretty sure. – Slava Nov 09 '17 at 14:14
  • 1
    @Slava - You are wrong. But since you seem unwilling to consider my experience as equal to yours, it's really a moot point. So I bid you a continued good day (or good night, depending on what your locale is). – StoryTeller - Unslander Monica Nov 09 '17 at 14:15
  • @StoryTeller " I'm with nwp, at least you know you have an object of the type, always, when you do uniform initialization." no you do not. – Slava Nov 09 '17 at 14:15
  • @Slava - Now you are just factually wrong. `T t{}` is always an object of type `T`. – StoryTeller - Unslander Monica Nov 09 '17 at 14:16
  • @StoryTeller `struct Foo { T t; Foo() }; Foo() : t{} {}` good luck to remember T when you write `Foo` constructor. – Slava Nov 09 '17 at 14:17
  • @Slava - You are becoming increasingly incoherent. For one thing it's `Foo::Foo() : t{} {}`. For another, I don't care what type `T` is, I care that `t` is an object, and not a function. Cheers. – StoryTeller - Unslander Monica Nov 09 '17 at 14:19
  • @StoryTeller you do care if `T` has a constructor with initializer list or not, that is the problem. And with fact that type could be defined in another file just adds beauty to it. – Slava Nov 09 '17 at 14:21
  • I think Slava's point is "You know you have an object of type `T`" is untrue because you may not know what `T` means at that point. That's not the issue, though. The point was that you have an _object_, not a function declaration (yeah, I know, a function pointer is an object too, but let's focus on meaning) – sehe Nov 09 '17 at 14:24
  • @sehe maybe I am not clear, `foo() : member( 5 ) {}` and `foo():member{5}{}` do those create the same object? I do not know if I do not know `member` type. – Slava Nov 09 '17 at 14:27
  • @Slava Moving the goal-posts slightly, (Twice: were talking about [`T {}`](https://stackoverflow.com/questions/47203577/compile-time-error-when-trying-to-invoke-function-pointer-to-member-functions?noredirect=1#comment81356694_47203577) and secondly `member{5}` is still an _object_ of the same type as `member(5)`). I think everyone participating here is aware of the fact that your concern is a valid concern and it was [immediately acknowledged](https://stackoverflow.com/questions/47203577/blurb?noredirect=1#comment81355692_47203577) – sehe Nov 09 '17 at 14:31
  • @sehe problem is "This has some issues with initializer lists being preferred to constructors, but that is an exception to the rule" is pretty misleading. That exception is much worse that benefit of using this rule. – Slava Nov 09 '17 at 14:33
  • Opinions. No one is going to prohibit you having your opinion. I happen to agree that having the wrong initializer is better than having the wrong type as well. And easier to deal with in most situations. Iff the MVP leads to compilation error, then you're lucky and the risk is lower. – sehe Nov 09 '17 at 14:34
  • @Slava How is that an argument for not using `{}`? You seem to think that initialization with `()` calls the correct constructor by definition while `{}` may or may not do the same. If you switch to `{}` creates an object and if that is a container of numbers (which you should know from the name alone) it will put a `5` into it, it will make more sense. Only if you need some weird constructor where the `5` means number of elements or something you need to look at the weird initialization with `()`. – nwp Nov 09 '17 at 14:34
  • @nwp for member initialization constructor, where 5 means number of elements is normal, and when it means one element with value 5 is weird. – Slava Nov 09 '17 at 14:41
  • @nwp anyway what is weird is matter of taste. But from my experience I disagree with your advise with "always use {}", so I expressed that. It is my opinion and it is not worse or better than yours. I just do not want inexperienced developer to think this is common practice and everybody agrees with it. – Slava Nov 09 '17 at 14:44
  • Possible duplicate of [Most vexing parse: why doesn't A a(()); work?](https://stackoverflow.com/questions/1424510/most-vexing-parse-why-doesnt-a-a-work) – YSC Nov 09 '17 at 14:46
  • Ho! I'm a bit late to the party... – YSC Nov 09 '17 at 14:49

1 Answers1

-2

A curly brace initialisation {} is called initialiser_list which is preferred in C++ because it can prevent some of the obvious errors. For example

char ch = 1234; // compiles.. though overflows

char ch1 {1234}; // compilation error

The code

 A a2();

constructs a2 as if we're calling a function... hence compile it not able to call the function pointer with this

Daksh Gupta
  • 7,554
  • 2
  • 25
  • 36
  • No, it's not always designating an initializer list off that bat, no questions asked. It depends on the type being constructed – StoryTeller - Unslander Monica Nov 09 '17 at 14:12
  • The problem with `A a2();` is not that it doesn't provide enough information. The problem is that it declares a function instead of constructing an `A`, which was intended. – nwp Nov 09 '17 at 14:13
  • `A a2();` is a function declaration; it says that there is a function named `a2` that takes no arguments and returns void. It doesn’t construct anything. – Pete Becker Nov 09 '17 at 14:14