I have a class, DBProc, which makes a connection to PostgreSQL, and allows user to submit queries/retrieve results.
Functionally, everything works.
The DBProc::connect() function takes an optional argument for connection type. The 3 variants are: direct, lazy, asynchronous.
I have code that instantiates the correct connection class according to user's choice. I initialize 3 unique_ptr<> beforehand, one for each possible connection class, then use an switch statement to choose the selected class type.
This all works fine...but
My preference would be to have ONE class var that holds a reference to
the connection class
(all the classes have the exact same functionality), but I see no easy way to do this.
'auto& currentConnection = lazyConnection' works fine in the switch statement, but of course goes out of scope after the code block.
If there was a way to create a var within a block and allow it to be seen outside the block, without 1st declaring it, that would work, but I don't believe that's possible in c++.
I can't declare it first because all these classes require initialization upon declaration.
So...c++atch 22 ;-)
So, every time I need to use the connection, I need a switch statement to select the right pointer.
I've looked at templates, unions, extern, and don't see a way to do it with any of these.
If anyone knows if there is a way to do this, please describe.
Here's a code snippet of class func:
bool DBProc::connect(ConnectionType type) {
...
unique_ptr<pqxx::connection> connect;
unique_ptr<pqxx::lazyconnection> lzy_connect;
unique_ptr<pqxx::asyncconnection> async_connect;
try
{
switch (type) {
case ConnectionType::direct : {
connect = make_unique<pqxx::connection>(connOpts);
break;
}
case ConnectionType::lazy : {
lzy_connect = make_unique<pqxx::lazyconnection>(connOpts);
break;
}
case ConnectionType::async : {
async_connect = make_unique<pqxx::asyncconnection>(connOpts);
break;
}
} catch
...
}
Working answer provided in comment by 'some programmer dude'
Why not have a std::unique_ptr to pqxx::connection_base which is the common base class for all connection types? – Some programmer dude
Simplified code:
unique_ptr<pqxx::connection_base> base_connect;
try
{
switch (type) {
case ConnectionType::direct : {
base_connect = make_unique<pqxx::connection>(connOpts);
break;
}
case ConnectionType::lazy : {
base_connect = make_unique<pqxx::lazyconnection>(connOpts);
break;
}
case ConnectionType::async : {
base_connect = make_unique<pqxx::asyncconnection>(connOpts);
break;
}
default:
error += "No valid connection type supplied (direct | lazy | async)";
return false;
break;
}
Related
In the following code, I'd expect that both references to System.Action type to be represented as a QualifiedNameSyntax but the second one is represented as a MemberAccessExpressionSyntax.
Is that correct? If so, why can't it be a QualifiedNameSyntax?
class Foo
{
public void M(object o)
{
var t = typeof(System.Action); // 1
switch(o)
{
case System.Action: // 2
break;
}
}
}
Generally you're only going to get a QualifiedNameSyntax in a Roslyn syntax tree where the only legal thing there is a qualified name; in those cases we're running a restricted parser that will only understand qualified names. Anything else we're running our generic expression parser which will spit out whatever expression is there, and we'll figure out what it actually is during binding. Because consider another case like:
SomeEnum e;
switch (e)
{
case SomeEnum.Blue: Console.WriteLine("Blue!"); return;
}
In that case the SomeEnum.Blue is absolutely an access to a member. But we don't actually know what "SomeEnum" is until binding, so we just always go with MemberAccessExpression.
I can't tell you why for sure, but here's one relevant thing to think about:
In legal code, I think you're right that a switch can never accept a MemberAccessExpression, and so a QualifiedNameSyntax would be sufficient to represent this.
However let's look at some illegal code, and see what happens:
class Foo
{
public static void M(object o)
{
var t = typeof(Foo.M(5)); // 1
switch(o)
{
case Foo.M(5): // 2
break;
}
}
}
This gives 4 errors for the first usage of Foo.M(5):
error CS1026: ) expected
error CS1002: ; expected
error CS1513: } expected
error CS0426: The type name 'M' does not exist in the type 'Foo'
And only 1 for the second:
error CS0426: The type name 'M' does not exist in the type 'Foo'
By allowing a more flexible grammar in the second case, error messages are much better, as they can be done at the semantic level rather than a syntax level.
Since switch expressions accept any pattern as a case, it's more likely that you'll write something invalid, so good error messages are more important in that case.
Currently I am having a function which has two arguments of type enums, the function requires to compare both and do particular task
example:
void set_Test_Status(Tests TestName, Status TestStatus)
{
switch(TestName)
{
case Tests::Test1:
{
switch(TestStatus)
{
case TestStatus::St1:
//Rest of Code
}
}
//Rest of Code
}
}
is it a good programming practice? or is there any alternative method or style of coding that i should be aware of? Thank you!
Edit:
Finally after trial and error, I did this. First i saw the maximum and minimum items in each enums, In my case TestName were 6 and TestStatus had 3. I created 3 functions setStatusRunning(Tests TestName), setStatusSelected(Tests TestName) and setStatusFinished(Tests TestName) and in set_Test_status, using switch(TestName) i check which function should be called and then called the appropriate functions. The reason i had to make set_Test_Status in the first place was to make easy for other classes, since i made set_Test_Status public and the other 3 as private.
It is truly a matter of opinion as having nested switch statements is valid c++ code. Some may not have problems with it while others may argue that it can be confusing.
My advice would be on the lines of this; if the code blocks within the case statements are short such as 1-2 lines and they are fairly easy to read and follow, then there should be nothing wrong with it. However, if the code is quite cumbersome and the nested switch statements spans well over 50 to 100+ lines then I would suggest refining your code and make functions out of them.
Examples:
// should be okay
unsigned int outerSwitch = someValue();
unsigned int innerSwitch = someOtherValue();
switch ( outerSwitch ) {
case 1: {
switch ( innerSwitch ) {
case 1 : {
// 1 or 2 lines okay;
}
case 2 : {
// 1 or 2 lines okay;
}
case 3 : {
// 1 or 2 lines okay;
}
default : {
}
} // inner switch when outer switch case = 1
}
case 2: {
// Same as case 1
}
case 3: {
// Same as case 1
}
default: {
}
} // outer switch
But as you have seen above with just 3 cases to the outer and inner; it gets very long very quickly and I haven't even expanded them all. So this can be frowned upon.
You can have a single switch as others have suggested that calls a specific function to that switch then within that function it has its own switch statement like this:
unsigned int someFuncA( unsigned int someVal ) {
switch ( someVal ) {
case 1 : {
// do this
// return that;
}
case 2: {
// ... etc.
}
} // switch
}
unsigned int someFuncB( int someVal ) {
// similar to someFuncA();
}
unsigned int someFuncC( int someVal ) {
// similar to someFuncA();
}
unsigned int switchValue = someValue();
unsigned int innerValue = someOtherFunction();
unsigned int temp = 0;
switch( switchValue ) {
case 1 : {
temp = someFuncA( innerValue );
// either return temp, break, continue, or fall through
}
case 2 : {
temp = someFuncB( innerValue );
// same as above
case 3 : {
temp = someFuncC( innerValue );
// same as above
}
default : {
// default stuff here
}
} // switch
Comparing the two you will see that the 2nd version is easier to read and less cumbersome than the 1st. Yes the first version is valid legal C++ code, but is frowned upon because of how messy it can easily and quickly get. So where ever you can; turn that code into a function that is designed to do just that one thing.
EDIT
Another possibility is to design specific functions to do a task and as you said that your function takes 2 different enumeration values, you can look up the concept of functions that are designed to take bit flags. You will see this kind of code quite a bit in windows programming as well as OpenGL.
Another option is this: consider that fact you have an outer control switch, and inner control switch. Even if you have multiple cases, each case is independent with a specific unique ID. The same can be said for the inner switch cases. Knowing this you can create an associative mapping of all the statements in a combined matter using std::multimap<unsigned, unsigned> testCases and with this lookup table you can have it in a single statement with independent function calls to each map entry. cppreference : std::multimap
Your map might look like this:
testCases[1][1];
testCases[1][2];
testCases[1][3];
testCases[2][1];
testCases[2][2];
testCases[2][3];
testCases[3][1];
testCases[3][2];
testCases[3][3];
Where each index of the map is the logic or calculation you want to perform.
It can be quite confusing for someone reading the code-- indentation helps, but it can still be difficult to follow where the case and switch statements start and end. Most IDEs have support for finding a matching brace, but finding a matching break isn't generally a thing, so it can be difficult to even see where a case statement ends. (And technically case doesn't define scope whereas braces do, so it doesn't even have an end.)
If you get misaligned braces or accidentally mismatch where they should be, you can have odd things happen. Languages like Ada try to prevent that with strongly typed English-language specifiers.
If you are doing a lot of sub-switches, I would put them into another function and call it with the information it needs, then you could do a switch statement inside the method which is more modular, separate scope and clear what is going on.
A good practice to keep code concise is to do only one thing in a function. Using a switch already is a smell that your function is going to do different things. It all depend of your specific case.
One thing to look at is: is it coherent to manage all these cases in one class. Should you have one class per possibility, with an interface forcing to implement a function, instead of doing all the possibilities in a switch case.
In case you want to keep the switch, a good practice would be to not put code in it other than the switch. Each case just calls a function. This will already make stuff more readable.
Finally, are you using all the cases? If no, you code could be more clear by just implementing the pairs of values that you need:
if(TestName == Tests::Test1 && TestStatus == TestStatus::St1)
{
doThing();
}
To summarize:
This might be a smell that your code needs to be split in more classes to have only one responsibility per class (too many if and/or too many switches ar a sign of that). If you are sure that you need a switch, keep it as simple and clear as possible
I am currently trying to figure out an alternative method for switch statements as the program I have the switch statements are getting really long and confusing. Therefore I thought it would be a good idea to use array of pointers to functions. I am using c++ and qt. But when I try and implement, I am getting the following error.
cannot convert 'CheckPl::comA' from type 'void (CheckPl::)()' to type 'void (*)()'
It would be much appreciated if someone would help me out with this or at least point me to correct direction.
[...] alternative method for switch statements as the program I have the switch statements are getting really long and confusing.
Extract each case block into a separate function; This way, the switch changes from a 10km long function to a dispatch function:
void dispatch_function()
{
switch(x)
{
case 1: do_case_1(); break;
...
case n: do_case_n(); break;
}
}
Therefore I thought it would be a good idea to use array of pointers to functions.
It's not a good idea (especially, not in the way you went about it - you are solving the xy problem). In C++, when you have a requirement for multiple functions that are called in similar conditions, you have the requirements for an abstract interface.
Your resulting client code should look like this:
std::vector<handlers> handlers; // filled with handler instances, one for each case
for(const auto& h: handlers) // replaces switch
if(h.fits_case(x)) // replaces case statement
{
h.do_case(x); // replaces case block
break;
}
It follows that your handler classes should inherit from a base class like this:
class handler_base
{
virtual bool fits_case(int x) = 0;
virtual void do_case(int x) = 0;
}
This is easy to understand (in both implementation and client code), it is modular, testable (you can test each case separately) and extensible (if you need a new case you only add the case and add it to the vector); It also doesn't use any pointers.
A pointer to a member function has to be stored in a variable of the appropriate type. A pointer to a member function is not compatible with a pointer to a function.
void (CheckPl::*mptr)() = &CheckPl::comA;
A pointer to a member function requires an instance to an object for invocation.
CheckPl c;
CheckPl *cp = &c;
(c.*mptr)();
(cp->*mptr)();
The hardest thing to remember about the above syntax is that the extra set of parentheses is required.
I am new to C++ and trying to learn the code for Extreme Tux Racer. In the code in the main method it says manager.Run(...). To me this looks like it is running the Run method of a manager object in the State namespace.
switch (g_game.argument) {
case 0:
State::manager.Run(SplashScreen);
break;
case 4:
g_game.toolmode = TUXSHAPE;
State::manager.Run(Tools);
break;
case 9:
State::manager.Run(OglTest);
break;
}
I assume that the manager object's run method has to be declared and defined somewhere. But I searched all of the included files for the word manager and could not find it. What am I missing here?
It looks like they set file name the same as class name, which is a good way to do. So in states.h, you could see all definition:
class State {
//...
static Manager manager; // manager is static member
//...
};
static member could be accessed by :: , . or -> operator.
State::manager.Run(..); // valid
State state;
state.manager.Run(..); // valid as well
State *pState = &state;
pState->manager.Run(..); // also valid
i use visual studi 2008. (c++)
in my switch case a wanted to create an object, but i doens't work.
is it right, that i can't create an object in a switch case?
if that's right,whats the best way to work around it,
a new method that's creates that object?
edit the code:
switch (causwahl){
case '1':
cAccount *oAccount = new cAccount (ID);
case '2' ....
I can't say for sure with such a vague question, but I'm guessing that you're doing something like this:
switch(foo)
{
case 1:
MyObject bar;
// ...
break;
case 2:
MyObject bar;
// ...
break;
}
This isn't allowed because each case statement has the same scope. You need to provide more scope if you want to use the same variable name:
switch(foo)
{
case 1:
{
MyObject bar;
// ...
break;
}
case 2:
{
MyObject bar;
// ...
break;
}
}
I suggest avoiding switch-case because of this and other problems. You can allow variable definitions by extra curly braces, but that looks messy and causes two levels of indentation. Other problems are that you can only use integer/enum values for cases, that the break statement cannot be used to break from a loop outside the switch. Forgetting to break is also a very common programming mistake that cannot be detected by the compiler (because it is still valid code) and it leads to hard to debug bugs.
Personally I only use switch-case with enum values, and even then never with a default label. This has the benefit of getting me a compile warning (from GCC) if not all possible values of the enum are handled.
There is nothing wrong with if-elses.
switch (choice)
{
case 1:
{
cout<<"\nBike object created********"<<endl;
Bike B1(2,4,50);
V=&B1;
V->Display_Details();
V->CallToll(persons);
break;
}
case 2:
{
cout<<"\n CAR object created********"<<endl;
Car C1(4,8,50);
V=&C1;
V->Display_Details();
V->CallToll(persons);
break;
}
default:
cout<<"You have entered an invalid choice...........Please Enter valid choice........"<<endl;
}