Pointer to method - c++

Anyone knows how to compile this example code under msvc2010 ? (supposedly compiles under GCC)
class cmdLine;
struct cmdList
{
const char *c;
const char *s;
const char *h;
void (cmdLine::*cmdFuncPtr)();
};
class cmdLine
{
public:
cmdLine();
static cmdList myCmdList[];
void test();
};
cmdLine::cmdLine()
{
}
void cmdLine::test()
{
}
cmdList cmdLine::myCmdList[] =
{
{"xxx", "yyy", "zzzzz", &cmdLine::test},
{"aaa", "bbb", "ccc", 0}
};
int _tmain(int argc, _TCHAR* argv[])
{
cmdLine c;
(c.myCmdList[0].*cmdFuncPtr) (); //error (why?)
}
I get error C2065: 'cmdFuncPtr' : undeclared identifier and dont know whats wrong ?

Use this syntax
(c.*c.myCmdList[0].cmdFuncPtr) ();
As cmdFuncPtr is a pointer to a method of cmdLine, it needs an instance of the class to be invoked on, which is c. At the same time, cmdFuncPtr is a member of cmdList, so it needs an instance of the class where it is stored, which is c.myCmdList[0]. That's why c shall be used twice in the expression.
The expression presented by OP parses as: "Invoke a method on an instance of a class in c.myCmdList[0] through a method pointer stored in a standalone variable cmdFuncPtr". Such variable doesn't exist, that's what the compiler complains about.

Related

what does a const char** look like?

I have a class which takes the main command line arguments (eg, -B, -a, etc) and does something with them, but also i would like to be able to instantiate that function without passing the command line arguments, so for example:
constructor:
myClass(int argc, const char **argv){
<initialise class with flags from argv>
}
myClass() : myClass(2, "-B") {}
}
Here i am trying to instantiate myClass with the flag "-B", but it keeps giving me the error:
no known conversion for argument 3 from ‘const char [3]’ to ‘const char**’
so i was wondering what i need to do to pass a value in as const char**?
First level is pointer to first pointer to char *. Second level is pointer to the first const char of c-string.
> cdecl explain "const char ** args"
declare args as pointer to pointer to const char
If you have -std=c++11 available, you can use this example (but it can be rewritten to use old standard):
#include <iostream>
#include <vector>
#include <string>
class test {
public:
test(const std::vector<std::string> & args) {
for (auto & arg : args) {
std::cout << arg << "\n";
}
}
test() : test{{"-B"}} {}
};
int main(int argc, const char ** argv) {
test sth{{argv+1, argc+argv}}; // skip program name here
test sth_else;
}
const char** is pointer to const char*. In your case, you intend to pass multiple arguments as part of argv, so you can pass something like below:
const char* argv[] = {"<program name>", "B"};
myClass m(2, argv);
Note: const char** x & const char* x[] are same. The 2nd syntax is helpful when one wants to "represent" an array.
Here I am giving a way to mimic the main(int, char**) function argument for your internal test. If you want to pass from default constructor to argument constructor then all the above stuff will have to go global.

What am i doing wrong here? Defining a class with a pointer to function typedef.

Here is my code:
// WorkDamnit.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
class Scheduler
{
public:
typedef void (*function_ptr) (void);
struct Task
{
function_ptr function;
int numOfTasks;
};
void Init(Task *tasks, int numOfTasks);
private:
int _numOfTasks;
Task *_tasks;
};
void Scheduler::Init(Scheduler::Task *tasks, int numOfTasks)
{
_tasks = tasks;
_numOfTasks = numOfTasks;
}
void count() {};
Scheduler::Task task_list =
{
count, 1
};
Scheduler scheduler;
Scheduler.Init(Scheduler::Task &task_list,1);
int _tmain(int argc, _TCHAR* argv[])
{
return 0;
}
I get the following errors from the compiler:
1>c:\users\evan\documents\visual studio 2012\projects\workdamnit\workdamnit\workdamnit.cpp(49): error C2143: syntax error : missing ';' before '.'
1>c:\users\evan\documents\visual studio 2012\projects\workdamnit\workdamnit\workdamnit.cpp(49): error C2059: syntax error : '.'
The compiler doesnt seem to like the line after the class object definition. When i try to call the init() member. All i can think of is that it has to do with the pointer to function reference. Maybe someone can shed some light on this for me?
You can call call functions/methods directly outside of other methods/functions.
Scheduler.Init(Scheduler::Task &task_list,1);
2 problems in this line.
The above seems to be outside of any function/method. For eg. you can put in inside main.
The line itself is not correct. So change it to
scheduler.Init(&task_list,1);
Usually you call a method on an object not a class name, except for static methods. You don't pass the parameter type while passing parameters to the method.
So the changed line in main will look like
int _tmain(int argc, _TCHAR* argv[])
{
scheduler.Init(&task_list,1);
return 0;
}
Line 49 should be:
scheduler.Init(Scheduler::Task &task_list,1); // note the lowercase 's': the object should be used, not the class
Also it should be within a function (maybe main in your case)

What does the 'hides constructor for' warning mean when compiling C++ with g++?

Using the following code:
#include <stdio.h>
struct my_struct {
int a;
int b;
my_struct();
};
my_struct::my_struct(void)
{
printf("constructor\n");
}
void my_struct(void)
{
printf("standard function\n");
}
int main (int argc, char *argv[])
{
struct my_struct s;
s.a = 1;
s.b = 2;
printf("%d-%d\n", s.a, s.b);
return 0;
}
I get a warning compiling with g++ -Wshadow main.cpp:
main.cpp:15:20: warning: ‘void my_struct()’ hides constructor for ‘struct my_struct’
I would be ok with that warning if the void my_struct function actually replaced the my_struct::my_struct one. But it does not appears to be the case. If I run the program, I get:
constructor
1-2
Any idea what this warning mean ? It is quite annoying especially when I include C headers into C++ code
The warning points out that the my_struct() function has the same name as the my_struct structure. It means you will be unable to write:
my_struct s; // Error.
Because the compiler will think that you're using a function as a type. However, as you probably realized, you can still instantiate your structure with the struct keyword:
struct my_struct s; // Valid.
void my_struct(void) has the same name of your class/struct and since it is in the global namespace it is conflicting with your class/struct's constructor.
You could try something like:
#include <cstdio>
struct my_struct {
int a;
int b;
my_struct();
};
my_struct::my_struct(void)
{
printf("constructor\n");
}
namespace mbonnin
{
void my_struct(void);
}
void mbonnin::my_struct(void)
{
printf("standard function\n");
}
int main (int argc, char *argv[])
{
my_struct s;
s.a = 1;
s.b = 2;
printf("%d-%d\n", s.a, s.b);
mbonnin::my_struct();
return 0;
}
And by the way the struct in struct my_struct s; is redundant in C++.
warning: ‘void my_struct()’ hides constructor for ‘struct my_struct’
Any idea what this warning mean ?
It means that sometimes the warnings issued by the GNU compiler suite are a bit off. (Try omitting the semicolon after the close brace on the definition of struct my_struct. If you are using anything but a very recent version of g++ the error message will be a bit off.)
Something is being hidden here, but it is not the constructor for struct my_struct. What is being hidden is the name my_struct as a type identifier. You can see this in action if you remove the struct from the declaration of the variable s: Use my_struct s; instead of struct my_struct s; Without the contextual information offered by the struct keyword, the compiler now must interpret my_struct as a function name.

member function pointer problem

Works:
static void WINAPI ServiceStart(DWORD argc, LPTSTR* argv);
int main() {
SERVICE_TABLE_ENTRY DispatchTable[] = {
{"MyService", ServiceStart},
{NULL, NULL}
};
}
Doesn't work:
error C2440: 'initializing' : cannot convert from 'void (__stdcall Service::* )(DWORD,LPTSTR *)' to 'LPSERVICE_MAIN_FUNCTIONA'
class Service {
static void WINAPI ServiceStart(DWORD argc, LPTSTR* argv);
};
int main() {
SERVICE_TABLE_ENTRY DispatchTable[] = {
{"MyService", Service::ServiceStart},
{NULL, NULL}
};
}
You must use & in that context to obtain a correct pointer.
Use &Service::ServiceStart, not Service::ServiceStart.
One piece of advice: since you made it a static function of Service class, rename it as well. ServiceStart is unnecessarily long. I think Service is implied here. If so, then make it just Start:
class Service
{
static void WINAPI Start(DWORD argc, LPTSTR *argv);
};
And then use &Service::Start.

How do you make C++ create an expression that uses compile-time checking for constants and asserts for variables?

Here’s an example setup… a macro or a template CHECKEXPR_RETURNVAL(EXPR,VAL) that checks that EXPR is TRUE while returning VAL.
This is useful in a variety of places -- like in this highly simplified example:
#define ISPOW2(VAL) ((0!=VAL)&&(0==(VAL&(VAL-1))))
#define _ALIGNPOW2(VAL,ALIGN) ((VAL+(ALIGN-1))&(~(ALIGN-1)))
#define ALIGNPOW2(VAL,ALIGN) CHECKEXPR_RETURNVAL( \
ISPOW2(ALIGN) , _ALIGNPOW2(VAL,ALIGN) )
So, the difficulty is this: I want to do compile time checks if possible, and if the value is not a constant that is determinate at compile time, then do a runtime check.
Basically, the idea is to catch bad parameters as soon as possible; if you can catch a bad parameter at compile time that's better than finding out at run time. Also, the compile time version is required for constant initializers.
Here are my two (failed) attempts to make single version work in multiple places (as a constant array size, as an enum initializer, and in a function with variables). Unfortunately, they either work for the compile time only (constant initializer) or the runtime only -- I would like to figure out a version that will work for both.
// CHECKEXPR_RETURNVAL - version "A"
#define CTCHECK_EXPR(EXP)(CTCheckBool<EXP>::ExistsZeroIfTrue)
template <bool bExpression> struct CTCheckBool {};
template <> struct CTCheckBool<true> {enum{ExistsZeroIfTrue=0};};
// Note: Plus ("+") is used rather than comma operator because
// the comma operator can not be used for constant initializers
#define CHECKEXPR_RETURNVAL_A(EXP,VAL) (CTCHECK_EXPR(EXP) + (VAL))
// Test Out version "A" -- works only for Compile Time Constants
#define ALIGNPOW2_A(VAL,ALIGN) CHECKEXPR_RETURNVAL_A( \
ISPOW2(ALIGN) , _ALIGNPOW2(VAL,ALIGN) )
char AlignedVar_A[ALIGNPOW2_A(2,8)];
enum { AlignedVal_A = ALIGNPOW2_A(57,16) };
int TestAlignPow2_A(int val, int align)
{return(ALIGNPOW2_A(val,align));} // Compile Error
// CHECKEXPR_RETURNVAL - version "B"
template<typename T> T CHECKEXPR_RETURNVAL_B(bool bExpr,T val)
{ ASSERT(bExpr); return(val); }
// Test Out version "B" -- works only for Runtime Computed Values
#define ALIGNPOW2_B(VAL,ALIGN) CHECKEXPR_RETURNVAL_B( \
ISPOW2(ALIGN) , _ALIGNPOW2(VAL,ALIGN) )
char AlignedVar_B[ALIGNPOW2_B(2,8)]; // Compile Error
enum { AlignedVal_B = ALIGNPOW2_B(57,16) }; // Compile Error
int TestAlignPow2_B(int val, int align)
{return(ALIGNPOW2_B(val,align));}
Unfortunately, neither version works for all three cases. Is there a code structure that will work for all the cases ?
It seems like you would really make use of c++0x constexpr functions...
Well... Not a complete answer, but I think you can derive what you want from this:
#include <stdio.h>
template <int I> struct S{
static void doIt(){
fprintf(stderr, "wow\n");
}
};
template<> void S<0>::doIt(){
fprintf(stderr, "oops\n");
}
#define EXPR(p) S<(int)((bool)(p))>::doIt()
int main(int argc, char** argv){
EXPR((5+2)==7);
EXPR((5+2)==8);
const int a = 58;
EXPR(a==58);
EXPR(58);
return 0;
}
You can get a compiler error based on expression:
#include <stdio.h>
template <int I> struct S{
static void doIt(){
ssdfkjehiu //deliberately invalid code
fprintf(stderr, "oops\n");
}
};
template<> void S<1>::doIt(){
fprintf(stderr, "wow\n");
}
#define EXPR(p) S<(int)((bool)(p))>::doIt()
int main(int argc, char** argv){
EXPR((5+2)==7);
EXPR((5+2)==8);//uncomment it to make code compile
const int a = 58;
EXPR(a==58);
EXPR(58);
return 0;
}
But the line that causes error will be in a middle of a lengthy template error message. Example:
1.cpp(6) : error C2065: 'asdlfkjhasd' : undeclared identifier
1.cpp(4) : while compiling class template member function 'void S<I>::doIt(void)'
with
[
I=0
]
1.cpp(19) : see reference to class template instantiation 'S<I>' being compiled
with
[
I=0
]
1.cpp(6) : error C2146: syntax error : missing ';' before identifier 'fprintf'
As you see, error is caused by line 19, which is mentioned in the middle of the message. This is a bit inconvenient.
I cannot guarantee that both examples doesn't rely on some undefined C++ behavior.
Also, I think that the next code maintainer may not be happy about this...
P.S. I think you should also take a look at boost. If I remember correctly, it had quite a lot of "magic preprocessor macro" (loops, for example), so it is possible that it implemented something similar.
--edit--
Okay, what about this one?:
#include <stdio.h>
#include <string>
template <typename T> void a(T &i){
fprintf(stderr, "variable\n");
}
void a(const char* const i){
fprintf(stderr, "constant\n");
}
void a(bool i){
fprintf(stderr, "constant\n");
}
int main(int argc, char** argv){
int i;
float f;
std::string s;
const char* s1 = "b";
a(3);
a(3+2);
a(1.0f);
a('a');
a("b");
a(i);
a(f);
a(s);
a(s1);
return 0;
}