This question already has answers here:
C/C++ changing the value of a const
(18 answers)
Closed 8 years ago.
I have a struct which is defined in types.h with the following code:
struct data_Variant {
FlightPlanSteeringDataRecord steeringData;
FlightPlanType flightPlan : 8;
MinitoteLegDataType legDataType : 8; // discriminent, either current or amplified
unsigned spare : 16;
union {
// currentLeg =>
CurrentLegDataRecord currentLegData;
// amplifiedLeg =>
AmplifiedLegDataRecord amplifiedLegData;
} u;
};
I am then trying to pass an instance of that struct as a parameter to a function in a C++ source file called dialogue.cpp:
void dialogue::update( const types::data_Variant& perfData){
...
}
I now want to change the value of some of the members of that struct inside this update() function. However, if I try doing this as I usually would, i.e.
perfData.etaValid = true;
I get a compile error which says: "C2166: l-value specifies const object". As I understand, this is because perfData has been declared as a constant variable. Am I correct in thinking this?
Since I didn't write this part of the code, but only want to use it to update the value displayed on the GUI, I don't really want to change the perfData variable by removing the const keyword, in case I break something else. Is there any way to change the value of a variable that has been declared as const?
I have tried declaring the same struct variable in another part of the code, without using the const keyword, to see if I can change the values of some of its members there... i.e. in Interface.cpp, I have added the following code to a function called sendData():
types::data_Variant& perfData;
perfData.steering.etaValid = true;
perfData.steering.ttgValid = true;
However, I now get the following compile errors on these lines:
error C2653: 'types' is not a class or namespace name
error C2065: data_Variant: undeclared identifier
error C2065: 'perfData': undeclared identifier
error C2228: left of '.steering' must have class/ struct/ union
Is there a way of updating the values of this struct? If so, how should I do it, and what am I doing wrong here?
I have added the following function to the dialogue.cpp source file, as suggested in the answer:
void dialogue::setFPTTGandETAValidityTrue(
FlightPlanMinitoteTypes::FlightPlanMinitoteData_Variant& perfData)
{
SESL_FUNCTION_BEGIN(setFPTTGandETAValidityTrue)
perfData.steeringData.fpETAValid = true;
perfData.steeringData.fpTTGValid = true;
SESL_FUNCTION_END()
}
You could add a wrapper for yourself.
void myupdate(dialogue& dia, types::data_Variant& perfData)
{
perfData.etaValid = true;
dia.update(perfData);
}
Then call myupdate() instead of dialogue::update().
You declare
void dialogue::update( const types::data_Variant& perfData){
...
}
that const is a declaration of you saying: "I won't modify the referenced object in this function". If you want to modify it in dialogue::update you have to remove the const keyword. Wrapping is not a solution, in my opinion, makes the code harder to maintain. Also I vote against remove const with const_cast.
The correct solution is to remove const from method declaration if you want to modify the referenced object inside that function.
Related
I was porting some legacy code to VS 2015 when this compiler error halted the build:
error C3867: 'OptDlg::GetFullModel': non-standard syntax; use '&' to create a pointer to member
Going to the corresponding file and line, I saw this:
Manager mgr = GetDocument()->GetManager();
OptDlg dlg;
...
mgr->SetFullModel(dlg.GetFullModel);
if ( dlg.GetFullModel )
mgr->SetSymm(...
GetFullModeland SetFullModel are the getter/setter pair for a member variable in two different classes:
class Manager {
...
bool GetFullModel() { return m_bFullModel; }
void SetFullModel(bool bFlag) { m_bFullModel = bFlag; }
....
};
class OptDlg {
...
void GetFullModel() { return m_bFullModel; }
void SetFullModel(bool bValue) { m_bFullModel = bValue; if ( bValue ) m_bInside = 0;}
Yep, something's wrong. Was dlg.GetFullModel supposed to be a pointer to a member function? I thought those use the class name, not an instance. Not to mention what that would mean for execution semantics...
C++ is still relatively new to me, so I tried Google. It had a lot on function pointers, but they all looked different from what I had:
&OptDlg::GetFullModel // Standard-compliant
vs
OptDlg::GetFullModel // The "normal" way to mess up getting a pointer to member, it seems
vs
dlg.GetFullModel // ?
Is dlg.GetFullModel just another way of getting a pointer to member function? If not, what is the "standard C++ version", if there is one? Is this just another one of those VS 6 "extensions"?
&OptDlg::GetFullModel // Standard-compliant
If your parameter types were supposed to be taking member functions, that's what you'd use. But they take booleans. It looks like you're just missing parentheses on your function calls, and it should be:
mgr->SetFullModel(dlg.GetFullModel());
if (dlg.GetFullModel())
mgr->SetSymm(...
Probably someone was ignoring warnings (or didn't have them on) and hence a pointer value (being produced through whatever shady means) was always being interpreted as non-NULL, hence boolean true.
Is this just another one of those VS 6 "extensions"?
It would appear to be the case, although this comment is the only documented evidence I can find it was an intentional/advertised "feature". Don't see any formal announcement of it being added or taken out.
It strongly looks to me like someone mis-typed dlg.GetFullModel() (which would call the function), not that they were trying to get a member function pointer.
Presumably the legacy compiler let it slide, taking the address of the function without using & and converting the non-null function pointer to bool (with value true) to pass into the set function.
I'm not going to get into too much of the details on the Excel side of things, I essentially took code from this example:
C++ app automates Excel (CppAutomateExcel)
solution1.cpp
So I've tried this code in MSVC and it compiles:
class foo { public: virtual void bar(){} };
int main()
{
void (foo::*p)() = &foo::bar;
}
But similar code to capture the address of the move function in Excel does not work:
int main()
{
Excel::_ApplicationPtr spXlApp;
HRESULT hr = spXlApp.CreateInstance(__uuidof(Excel::Application));
Excel::WorkbooksPtr spXlBooks = spXlApp->Workbooks;
Excel::_WorkbookPtr spXlBook = spXlBooks->Add();
Excel::_WorksheetPtr spXlSheet = spXlBook->ActiveSheet;
HRESULT(Excel::_Worksheet::*pMove)(...) = &spXlSheet->Excel::_Worksheet::Move;
<... irrelevant code ...>
return 0;
}
This has the following compiler error:
error C2276: '&': illegal operation on bound member function expression
If I remove the &, it says I should add it back:
error C3867: 'Excel::_Worksheet::Move': non-standard syntax; use '&' to create a pointer to member
Any help on what to do here would be greatly appreciated.
You say in your question "but similar code..." and then you show code in which you do not do the same thing. Try using the same syntax for setting pMove as you used for setting p in your smaller example. Try something like &Excel::_Worksheet::Move; (without the "spXlSheet->").
If you can specify the specific instance of the object for which to call the function pointer at the time that you set the function pointer as you have there, I'm not aware of such a capability. After dropping spXlSheet-> from where you set the variable, use it instead where you want to call the function pointer.
You need to declare the method pointer like this instead:
// or whatever parameter type Move() actually uses...
void (Excel::_Worksheet::*pMove)(tagVARIANT, tagVARIANT) = &Excel::_Worksheet::Move;
Then, to actually call pMove(), you would have to do something like this:
Excel::_WorksheetPtr spXlSheet = ...;
(spXlSheet.Get()->*pMove)(...);
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.
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 don't think my question is a duplicate of this one.
what I try to do:
template<const char* szFunctionName>
class CReentranceLock
{
public:
CReentranceLock(){}
~CReentranceLock(){}
bool isLocked(){return s_bLock;}
void setLocked(bool b)
{
const bool Result=(bool)InterlockedCompareExchange(
(unsigned long *)&s_bLock, b, !b);
}
private:
static bool s_bLock;
};
template<const char* szFunctionName>
bool CReentranceLock<const char*szFunctionName>::s_bLock=false;
// error C2146: syntax error : missing ',' before identifier 'szFunctionName'
implying that all instances of CReentranceLock would have their own static, relying on the const char address of the function name passed as a parameter of the template.
and that could be used like this:
void CMyObject::InAnyFunction()
{
const char* szFunctionName = __FUNCTION__;
CReentranceLock<szFunctionName> lock; // Edit: <- this doesn't work
if(lock.isLocked()) return;
lock.setLocked(true);
/// business code
lock.setLocked(false);
}
well that's only the theory...
and unfortunately this doesn't compile under visual 2010, at the line where I try to initialize the statics.
error C2146: syntax error : missing ',' before identifier 'szFunctionName'
what am I doing or thinking wrong ?
PS: and I am not dealing with the fact that reentrance is smelling like an awful design (in MFC), I know, I am lost in the middle of it ;-)
Edit: though the answer below is good, and the definition compiles... my use in CMyObject::InAnyFunction() with a const char * as a template-parameter available at compile time seems to be wrong. :-(
bool CReentranceLock<const char*szFunctionName>::s_bLock=false;
This should be:
bool CReentranceLock<szFunctionName>::s_bLock=false;
Just change the line to
bool CReentranceLock<szFunctionName>::s_bLock=false;