MFC's message map, no need of &? - c++

I've been looking for the answer to this question but it seems quite difficult to get it, which brings me finally here.
It's a syntax that we have to put the & right before pointer to member function.
For example here.
class Test;
typedef void (Test::*fpop)();
class Test
{
public:
void Op1(){}
};
int main(){
fpop pFunc;
pFunc = &Test::Op1; // we must need the &
return 0;
}
However, when I take a look at ON_COMMAND(or any other messages) in MFC, it seems a bit different from what I think is right.
VS6.0 is okay. It follows the right syntax as you see below.
You can clearly see & before memberFxn.
#define ON_COMMAND(id, memberFxn) \ // VS6.0
{ WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, AfxSig_vv, (AFX_PMSG)&memberFxn },
// ON_COMMAND(id, OnFoo) is the same as
// ON_CONTROL(0, id, OnFoo) or ON_BN_CLICKED(0, id, OnFoo)
But in VS2008, it goes a bit weird. There is no & before memberFxn.
#define ON_COMMAND(id, memberFxn) \ // VS2008
{ WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, AfxSigCmd_v, \
static_cast<AFX_PMSG> (memberFxn) },
// ON_COMMAND(id, OnBar) is the same as
// ON_CONTROL(0, id, OnBar) or ON_BN_CLICKED(0, id, OnBar)
Moreover, in spite of the fact that there is no & before memberFxn,
each line below works perfectly.
ON_COMMAND(ID_APP_ABOUT, CSingleApp::OnAppAbout) // &
ON_COMMAND(ID_APP_ABOUT, &CSingleApp::OnAppAbout) // no &
I tried to find why, and I was curious if it could be because of static_cast<> but it turned out that static_cast has nothing to do with it.
So I am wondering why in VS2008 I have 2 choices where I put the & or I don't have to put the &.

The Visual C++ compiler (VS2005 and VS2008) requires an ampersand (&) and the fully qualified name to form a pointer to member as per C++ standard as shown:
class Test
{
public:
void Foo() {}
void Bar()
{
void (Test::*ptr1)() = Foo; // C3867
void (Test::*ptr2)() = &Foo; // C2276
void (Test::*ptr3)() = Test::Foo; // C3867
void (Test::*ptr4)() = &Test::Foo; // OK
}
};
Most likely there are #pragmas in the MFC headers or something that suppresses the errors, for backwards compatibility reasons. Older versions of VC++ were much less conforming than the newer compilers.

The only correct way to form a pointer to member in C++ is with & and the class qualifier (in this case CSingleApp::).
The Visual C++ compiler has always been more relaxed and has allowed things not normally permitted in the language such as leaving of the qualifier when forming the pointer from inside the class' context and not needing to use & when it is strictly required.

Related

Why doesn't C++ allow const after ::?

Folks,
Problem Statement - Does C++ allow a (static) const be limited to a class scope, so I can get rid of #defines that pollute entire namespace?
My observation is NO (in the following DIFFERENT examples), and I'd like to find out why and what's the best alternative. VS generates error C2589: 'const' : illegal token on right side of '::'
EXAMPLE1
// a.h
class A
{
…
..
static const uint_32 myConst = 1234;
};
//b.cpp
include “a.h”
…
B()
{
uint32_t arr[A::myConst]; // C2589! const : illegal token on right side of '::'
}
EXAMPLE 2
// a.h
class A
{
…
..
enum blah
{
...
myConst = 1234,
..
};
};
//b.cpp
include “a.h”
...
B()
{
uint32_t arr[A::myConst]; // C2589! const : illegal token on right side of '::'
}
When you take your macro:
#define CONST 1234
and substitute it for where you use it:
static const int CONST = 1234;
The end result is nonsense:
static const int 1234 = 1234;
In another instance:
Int a1[a::CONST];
This also becomes nonsense:
Int a1[a::1234];
This all begs the question, what are you trying to do?
It looks like you're trying to create a member variable with the same name as your macro, CONST, here:
class A
{
static const int CONST = 1234;
};
However since when this code is compiled the macro has already been defined, the preprocessor changes this by substituting the macro before the compiler itself can get a crack at it. By the time the code is compiled, it looks like this:
class A
{
static const int 1234 = 1234;
};
Best is to just do away with the macro entirely, and then retrofit your code to use proper constants like you're trying to do here. Don't mix and match. At the very least, don't use the same name for the member as you do for the macro.
First of all your class is called A, as in capital A, not a. The class name is used to qualify the constant you are trying to use. So, change your code to use A::CONST. By the way, this is C++ not C# or Java, so there is no such thing as an Int, unless for some bizarre reason you decided to invent your own integer type.
As an aside, using all caps to name constants can collide with macros and is a good way to get into trouble, especially since pre-processing happens first and macros are substituted for all cases of the constants. This can often lead to invalid C++ code with syntax errors that are difficult to understand. That's why you should never use all caps to name constants, since this is a convention most commonly used for macros.
If I may make a guess, it looks like you're trying to use :: the same way you use . in Python.
It looks like you really don't understand what the scope resolution operator does, or how it works.
:: has a very specific, and quite limited usage. Until you understand it better, we're going to have a really hard time helping you.

Are there any scenarios where C4172 Visual C++ warning should not be considered an error?

There's C4172 Visual C++ warning for cases when a function returns an address of a local or temporary or a reference to a local variable.
Something like this:
int& fun()
{
int var;
return var; //C4172
}
Now looks like it is a good idea to use #pragma warning to make Visual C++ treat C4172 as error and break compilation.
Are there any sane scenarios where C4172 is not actually an error?
I'm not sure why anyone would ever want to do this:
int * stackTester()
{
int dummy;
return &dummy;
}
bool stackGoesUp()
{
int dummy;
return stackTester() > &dummy;
}
But generally speaking, you should treat the warning like an error.
It is a level 1 warning, very hard to ignore. But the compiler is following language standards here, invoking UB is not forbidden. And it is a very common bug that too often does come to a good end. The pointed-to stack location stays stable as long as you don't make any function calls.
The best way to deal with this is to always turn warnings into errors. Compile with /WX, "Treat warnings as errors" setting in the IDE. If you then intentionally want to suppress a warning then #pragma warning makes it clear to everybody that something fishy is going on that was thought about and not an accident.
Unused code
class base
{
virtual blah& makeBlah()
}
class red : public base
{
blah& makeBlah() { return blah(); } // there are no red blahs, never called
}
class blue : public base
{
blah& makeBlah() { actual code to make a blah }
}

Insufficient contextual information to determine type

I've done research and I can't make sense of this message at all. Everything I find seems to be a bug with the compiler itself. I've also read somewhere 'insufficient contextual information to determine type' is not a helpful message.
My question: Does anyone have information on what this compile error message means?
I understand this question might be code specific. My code merely declares a global anonymous struct, and then once it tries to access it in a function I get this error (or so I've evaluated it).
EDIT: I got my code to compile! - But I still don't know what the error means, so I'll leave the question open.
EDIT: Here's my code, as far as I'd suppose is important:
typedef ofstream::pos_type ofilepos;
struct stack // stack is my own stack data-structure
{
// ...
// int L; struct N *l;
stack(): L(0), l(NULL) {}
}
// ...
struct
{
const char* zero;
stack<ofilepos> chunks; // it was 'chunks();' with (), and it didn't work
} _fileext = {"\0\0\0"};
// ...
ofstream& write_stack_pushsize(ofstream& f)
{
_fileext.chunks.push(new ofilepos(f.tellp()));
f.write(_fileext.zero,4);
return f;
}
I think it might have been because I was calling a constructor in a struct declaration, rather than later... or something... it could be a bug in C++03.
Regarding this code,
struct
{
const char* zero;
stack<ofilepos> chunks();
} _fileext = {"\0\0\0"};
there is no way to provide a definition of the chunks member function after the anonymous struct definition.
Considering also the following usage example,
ofstream& write_stack_pushsize(ofstream& f)
{
_fileext.chunks.push(new ofilepos(f.tellp()));
f.write(_fileext.zero,4);
return f;
}
apparently you meant to define chunks as a data member instead of as a function member.
By the way, using underscore at the start of a name can possibly conflict with names in the implementation of the standard library. E.g. these names are reserved in the global namespace (if I recall correctly). The usual convention is instead to have an underscore at the end of a name, to signify "member".
To signyfy "global" I simply use a namespace that I call g. :-)

I need advice about a LNK2019 workaround

As previously discussed here, I'm trying to find a workaround for the LNK2019 issue that arises when building a static library which utilizes C++ templates, and separating the source from the header to keep the code private from other projects. I believe I've nearly come to a working conclusion (for my particular situation), but I'm not entirely sure if this is the correct/best way to go about it and was wondering if anyone has any suggestions, improvements/comments to add?
The goal is to do some type checking to see if the template's signature matches the target prototype function's signature, do some private processing, and return whether or not it was sucessful. NOTE that I have removed SdkHookMgr.h and SdkHookMgr.cpp from the prior version of the solution in the above link, and merged everything back into SdkLib.h and SdkLib.cpp, into a static class for a bit of clarity.
SdkLib.h:
#include <typeinfo>
#ifdef MY_EXPORTS
# define MYDECL __declspec(dllexport)
#else
# define MYDECL
#endif
// Prototypes
typedef HMODULE (WINAPI *HookLoadLibraryA)( LPCSTR lpFileName );
//...
class CHook;
class CHookManager;
MYDECL BOOL WINAPI ValidateHook( CHook *hook );
class CHook
{
public:
CHook() : m_type(NULL), m_target(NULL), m_result(FALSE) {};
CHook( const char *type, PVOID target ) : m_type(type), m_target(target) {
m_result = ValidateHook(this);
};
const char *m_type;
PVOID m_target;
BOOL m_result;
};
class CHookManager
{
public:
template <typename HookFunction> static BOOL Hook(HookFunction target)
{
const type_info& type = typeid(HookFunction);
CHook *hook = new CHook( type.name(), target );
return hook->m_result;
}
};
SdkLib.cpp:
#include <SdkLib.h>
IDXDECL BOOL WINAPI ValidateHook( CHook *hook )
{
// Do type checking, private processing, etc here...
return TRUE;
}
DemoDLL.cpp:
#include <SdkLib.h>
HMODULE WINAPI Hooked_LoadLibraryA( LPCSTR lpFileName )
{
DebugBreak();
}
// The function that starts the rollercoaster.
// - Syntax: Hook< prototype >( target )
if!(CHookManager::Hook<HookLoadLibraryA>(Hooked_LoadLibraryA))
cout << "Failed to create hook for LoadLibraryA!" << endl;
You may find that the results of typeid are not consistent between the DLL and the main program. (See, for example, typeid result across different dll's.)
Since your list of possible hooks is limited, it strikes me that overloaded functions would be a better choice than templates. You'd then have no DLL issues, and the validity of each hook would be checked at compile time. Here's an example of the sort of thing I'm thinking of; obviously in practice you'd split this into separate definition and declaration, with the definitions living in the DLL so it's all cleanly separated out.
class CHookManager {
public:
BOOL Hook(HookLoadLibraryA hook) {
assert(sizeof hook<=sizeof(uintptr_t));
return ValidateHook((uintptr_t)hook,"LoadLibraryA");
}
BOOL Hook(HookLoadLibraryW hook) {
assert(sizeof hook<=sizeof(uintptr_t));
return ValidateHook((uintptr_t)hook,"LoadLibraryW");
}
};
(Note that this shows up one disadvantage of this approach - you can only have one hook per function signature. I mention this for completeness' sake, but I'll assume this hasn't proven an issue.)
(You might like to replace the assert with a compile-time assert, if you have one.)
ValidateHook would use strcmp to figure out which hook is being hooked. Once it's figured out which hook it is, it would then cast the uintptr_t to the appropriate function pointer type. It knows the pointer was originally of the correct type for that hook, because you're using the C++ overload mechanism to do it all. (Or you could have an enum, say, for all the hook types, rather than passing in a string - it's up to you. The key part is that you have full control over the values being passed, so that the DLL and the calling code are definitely using matching values.)
This code would be a little tiresome to generate, but if you already have the list of typedef names then you could create the corresponding code using regular expression search and replace, or keyboard macros, in your editor of choice. Or you could use something like the so-called "X-Macro" to automate the generation of the whole thing.

Avoid warning 'Unreferenced Formal Parameter'

I have a super class like this:
class Parent
{
public:
virtual void Function(int param);
};
void Parent::Function(int param)
{
std::cout << param << std::endl;
}
..and a sub-class like this:
class Child : public Parent
{
public:
void Function(int param);
};
void Child::Function(int param)
{
;//Do nothing
}
When I compile the sub-class .cpp file, I get this error
warning C4100: 'param' : unreferenced formal parameter
As a practice, we used to treat warnings as errors. How to avoid the above warning?
Thanks.
In C++ you don't have to give a parameter that you aren't using a name so you can just do this:
void Child::Function(int)
{
//Do nothing
}
You may wish to keep the parameter name in the declaration in the header file by way of documentation, though. The empty statement (;) is also unnecessary.
I prefer using a macro, as it tells not only the compiler my intention, but other maintainers of the code, and it's searchable later on.
The method of commenting out the argument name can easily be missed by people unfamiliar with the code (or me 6 months later).
However, it's a style-issue, neither method is "better" or more optimal with regards to code generated, performance or robustness. To me, the deciding factor is informing others of my intent through a standardized system. Omitting the parameter name and putting in a comment would work equally well:
void CFooBar::OnLvnItemchanged(NMHDR *pNMHDR, LRESULT *pResult)
{
UNREFERENCED_PARAMETER(pNMHDR);
Alternatively:
void CFooBar::OnLvnItemchanged(NMHDR* /* pNMHDR */, LRESULT *pResult)
{
// Not using: pNMHDR
I would say that the worst solution is suppressing the warning message; that that will affect your entire file or project, and you'll lose the knowledge that maybe you've missed something. At least by adding the macro, or commenting out the argument name, you've told others that you've made a conscious decision to not use this argument and that it's not a mistake.
The Windows SDK in WinNT.h defines UNREFERENCED_PARAMETER() along with DBG_UNREFERENCED_PARAMETER() and DBG_UNREFERENCED_LOCAL_VARIABLE(). They all evaluate to the same thing, but the difference is that DBG_UNREFERENCED_PARAMETER() is used when you are starting out and expect to use the parameter when the code is more complete. When you are sure you'll never use the parameter, use the UNREFERENCED_PARAMETER() version.
The Microsoft Foundation Classes (MFC) have a similar convention, with the shorter UNUSED() and UNUSED_ALWAYS() macros.
Pick a style and stick with it. That way later on you can search for "DBG_UNREFERENCED_PARAMETER" in your code and find any instances of where you expected to use a argument, but didn't. By adopting a consistent style, and habitually using it, you'll make it easier for other and yourself later on.
Another technique that you can use if you want to keep the parameter name is to cast to void:
void Child::Function(int param)
{
(void)param; //Do nothing
}
As #Charles Bailey mentioned, you can skip the parameter name.
However, in certain scenarios, you need the parameter name, since in debug builds you are calling an ASSERT() on it, but on retail builds it's a nop. For those scenarios there's a handy macros (at least in VC++ :-)) UNREFERENCED_PARAMETER(), which is defined like this:
#define UNREFERENCED_PARAMETER(x) x
Note that the simple cast #R Samuel Klatchko posted also works, but I personally find it more readable if the code is explicit that this is an unreferenced parameter vs. simple unexplained cast like that.
Pragma works nicely too since it's clear you are using VS. This warning has a very high noise to benefit ratio, given that unreferenced parameters are very common in callback interfaces and derived methods. Even teams within Microsoft Windows who use W4 have become tired of its pointlessness (would be more suitable for /Wall) and simply added to their project:
#pragma warning(disable: 4100)
If you want to alleviate the warning for just a block of code, surround it with:
#pragma warning(push)
#pragma warning(disable: 4100)
void SomeCallbackOrOverride(int x, float y) { }
#pragma warning(pop)
The practice of leaving out the parameter name has the downside in the debugger that you can't easily inspect by name nor add it to the watch (becomes confused if you have more than one unreferenced parameter), and while a particular implementation of a method may not use the parameter, knowing its value can help you figure out which stage of a process you are in, especially when you do not have the whole call stack above you.
Since C++17 you also can use [[maybe_unused]] to avoid such warnings:
class Parent
{
public:
virtual void Function([[maybe_unused]] int param);
};
I would use a macro to suppress the unreferenced formal parameter warning:
#define UNUSED( x ) ( &reinterpret_cast< const int& >( x ) )
This has the following advantages:
Unlike #define UNUSED( x ) ( void )x, it doesn't introduce a need for the full definition of the parameter's type to be seen where no such need may have existed before.
Unlike #define UNUSED( x ) &x, it can be used safely with parameters whose types overload the unary & operator.
What about just adding reference with a comment:
void Child::Function(int param)
{
param; //silence unreferenced warning
}
This was also suggested here: https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-4-c4100?view=vs-2019