I write glsl wrapper for education purposes, but I stopped because I have some misunderstanding. When I want insert variable to specific location, I have mismatch warning. Because location is GLint, but glVertexAttrib location must be GLuint.
Here's my code sample
bool Material::AddAttrib(GLchar *variable, std::vector<GLdouble> values) {
GLint location = glGetAttribLocation(program,variable);
GLenum error = glGetError();
bool isNor = PrintError(error);
if(!isNor) return isNor;
switch (values.size()) {
case 1:
glVertexAttrib1d(location, values.at(0));
break;
case 2:
glVertexAttrib2d(location, values.at(0), values.at(1));
break;
case 3:
glVertexAttrib3d(location, values.at(0), values.at(1), values.at(2));
break;
case 4:
glVertexAttrib4d(location, values.at(0), values.at(1), values.at(2), values.at(3));
break;
default:
PrintErrorSize();
return false;
}
error = glGetError();
isNor = PrintError(error);
return isNor;
}
glGetAttribLocation() may return negative indices in case of an error. Of course, a negative index is not valid if used for glVertexAttrib...(). That's why there is a type mismatch. You can resolve this with a simple cast:
GLint retrievedLocation = glGetAttribLocation(program,variable);
if(retrievedLocation < 0)
return ...; //there is no variable with this name
GLuint location = (GLuint) retrievedLocation;
Related
I'm generating a trade request that's causing a 10013 error when I do backtesting in MT5. I decided to log the trade request and it printed this:
2022.11.16 14:28:17.245 Core 01 2022.01.04 11:00:00 Action REMOVE, Symbol EURUSD, Volume 0.100000, Price 1.128980, Deviation 5, Type SELL STOP LIMIT, Position 9443944
My code is:
bool Strategy::DoEntryRules() {
// Iterate over all the entry rules we have registered...
for (int i = 0; i < m_entry_rules.Count(); i++) {
IEntryRule *rule;
m_entry_rules.TryGetValue(i, rule);
EntryResult result = rule.Enter();
if (result.Result == ENTRY_RESULT_CONTINUE) {
continue;
} else if (result.Result == ENTRY_RESULT_ERROR) {
PrintFormat("Entry rule %s failed with error code %d\n", rule.Name(), result.ErrorCode);
}
m_money_manager.AssignLot(result.Order);
uint errCode = SendOrder(result.Order, rule.Name());
if (errCode != 0) {
result.Result = ENTRY_RESULT_ERROR;
result.ErrorCode = errCode;
}
return true;
}
return false;
}
uint Strategy::SendOrder(const MqlTradeRequest &request, const string name) {
string action;
switch (request.action) {
case TRADE_ACTION_DEAL:
action = "DEAL";
case TRADE_ACTION_SLTP:
action = "SLTP";
case TRADE_ACTION_CLOSE_BY:
action = "CLOSE BY";
case TRADE_ACTION_MODIFY:
action = "MODIFY";
case TRADE_ACTION_PENDING:
action = "PENDING";
case TRADE_ACTION_REMOVE:
action = "REMOVE";
}
string type;
switch (request.type) {
case ORDER_TYPE_BUY:
type = "BUY";
case ORDER_TYPE_BUY_LIMIT:
type = "BUY LIMIT";
case ORDER_TYPE_BUY_STOP:
type = "BUY STOP";
case ORDER_TYPE_BUY_STOP_LIMIT:
type = "BUY STOP LIMIT";
case ORDER_TYPE_CLOSE_BY:
type = "CLOSE BY";
case ORDER_TYPE_SELL:
type = "SELL";
case ORDER_TYPE_SELL_LIMIT:
type = "SELL LIMIT";
case ORDER_TYPE_SELL_STOP:
type = "SELL STOP";
case ORDER_TYPE_SELL_STOP_LIMIT:
type = "SELL STOP LIMIT";
}
PrintFormat("Action %s, Symbol %s, Volume %f, Price %f, Deviation %d, Type %s, Position %d",
action, request.symbol, request.volume, request.price, request.deviation, type, request.position);
MqlTradeCheckResult checkResult;
if (!OrderCheck(request, checkResult)) {
PrintFormat("%s generated a bad order with error code %d: %s", name, checkResult.retcode, checkResult.comment);
return checkResult.retcode;
}
MqlTradeResult result;
if (!OrderSend(request, result) && result.retcode != TRADE_RETCODE_DONE) {
PrintFormat("%s generated an order that was not accepted with error code %d: %s", name, result.retcode, result.comment);
return result.retcode;
}
return 0;
}
where m_entry_rules contains one IEntryRule, which is an interface that has the following implementation:
EntryResult SentimentEntry::Enter() {
EntryResult result;
if (m_handle == 0) {
int errCode = InitATR();
if (errCode != 0) {
result.Result = ENTRY_RESULT_ENTER;
result.ErrorCode = errCode;
return result;
}
}
double values[];
if (CopyBuffer(m_handle, 0, 0, 1, values) < 0) {
result.Result = ENTRY_RESULT_ERROR;
result.ErrorCode = GetLastError();
ResetLastError();
return result;
}
ENUM_SENTIMENT sentiment = SentimentIndicator();
bool decision = GetRange() > 0.66 * values[0];
if (decision && sentiment != SENTIMENT_NEUTRAL) {
PrintFormat("%f > 0.66 * %f, %s", GetRange(), values[0], SentimentToString(sentiment));
result.Result = ENTRY_RESULT_ENTER;
result.Order = CreateOrder(m_magic);
if (sentiment == SENTIMENT_BULLISH) {
result.Order.price = SymbolInfoDouble(Symbol(), SYMBOL_ASK); // ENTERED HERE
result.Order.type = ORDER_TYPE_BUY;
} else if (sentiment == SENTIMENT_BEARISH) {
result.Order.price = SymbolInfoDouble(Symbol(), SYMBOL_BID);
result.Order.type = ORDER_TYPE_SELL;
}
} else {
result.Result = ENTRY_RESULT_CONTINUE;
}
return result;
}
and m_money_manager.AssignLot is defined as:
void ConstantLotManager::AssignLot(MqlTradeRequest &request) {
request.volume = 0.1;
return;
}
Finally, the CreateOrder function is defined as:
MqlTradeRequest CreateOrder(ulong magic) {
MqlTradeRequest request;
request.symbol = Symbol();
request.deviation = 5;
request.action = TRADE_ACTION_DEAL;
request.type_filling = ORDER_FILLING_FOK;
request.type_time = ORDER_TIME_GTC;
request.magic = magic;
return request;
}
From logging, I'm able to determine that the commented line was reached, so the trade request should have an action of TRADE_ACTION_DEAL and a type of ORDER_TYPE_BUY so I'm not sure why it's showing up as me attempting to remove a sell-short order. Does anyone know what's going on here?
I have determined the problem and fixed it. The core issue was that I wasn't converting the ENUM_TRADE_REQUEST_ACTIONS and ENUM_ORDER_TYPE enums to strings properly, giving me the impression of a malformed trade request. The logging statement should look like this:
string action;
switch (request.action) {
case TRADE_ACTION_DEAL:
action = "DEAL";
break;
case TRADE_ACTION_SLTP:
action = "SLTP";
break;
case TRADE_ACTION_CLOSE_BY:
action = "CLOSE BY";
break;
case TRADE_ACTION_MODIFY:
action = "MODIFY";
break;
case TRADE_ACTION_PENDING:
action = "PENDING";
break;
case TRADE_ACTION_REMOVE:
action = "REMOVE";
break;
}
string type;
switch (request.type) {
case ORDER_TYPE_BUY:
type = "BUY";
break;
case ORDER_TYPE_BUY_LIMIT:
type = "BUY LIMIT";
break;
case ORDER_TYPE_BUY_STOP:
type = "BUY STOP";
break;
case ORDER_TYPE_BUY_STOP_LIMIT:
type = "BUY STOP LIMIT";
break;
case ORDER_TYPE_CLOSE_BY:
type = "CLOSE BY";
break;
case ORDER_TYPE_SELL:
type = "SELL";
break;
case ORDER_TYPE_SELL_LIMIT:
type = "SELL LIMIT";
break;
case ORDER_TYPE_SELL_STOP:
type = "SELL STOP";
break;
case ORDER_TYPE_SELL_STOP_LIMIT:
type = "SELL STOP LIMIT";
break;
}
PrintFormat("Action %s, Symbol %s, Volume %f, Price %f, Deviation %d, Type %s, Position %d",
action, request.symbol, request.volume, request.price, request.deviation, type, request.position);
This was my punishment for not remembering that I have to break switch statements in C++. :(
i am trying to figure out a way in esp32 to have (a list) for lack of better terms, that i could call upon as a variable input. I have a void playwav(); function. I want to use a global variable to define the file that should be played. ie playwav('alarm'). I had a case switch setup but was using the a b c method. As my code is growing (next step is going to add 71 new wav files), i am quickly realizing that method will no longer work. I have been told to do an array but for the life of me no matter what ive read i just cant grasp how to do it nor call upon the files by name. Does anyone have advice on what i should do? Any help is much appreciated.
This is what i currently have.
void playWAV (char effect, int bg1248_general_volume)
{
Serial.println("Entered playWAV");
switch (effect)
{
case 'a':
file = new AudioFileSourceSD("/wav/alarm.wav");
break;
case 'b':
file = new AudioFileSourceSD("/wav/alarmhigh.wav");
break;
case 'c':
file = new AudioFileSourceSD("/wav/alarmlow.wav");
break;
case 'd':
file = new AudioFileSourceSD("/wav/error.wav");
break;
case 'e':
file = new AudioFileSourceSD("/wav/error1.wav");
break;
case 'f':
file = new AudioFileSourceSD("/wav/noread.wav");
break;
case 'g':
file = new AudioFileSourceSD("/wav/noreadings.wav");
break;
case 'h':
file = new AudioFileSourceSD("/wav/normalrange.wav");
break;
case 'i':
file = new AudioFileSourceSD("/wav/warning.wav");
break;
case 'j':
file = new AudioFileSourceSD("/wav/warninghigh.wav");
break;
case 'k':
file = new AudioFileSourceSD("/wav/warninglow.wav");
break;
case 'l':
file = new AudioFileSourceSD("/wav/startup.wav");
break;
case 'm':
file = new AudioFileSourceSD("/wav/startup.wav");
break;
case 'n':
file = new AudioFileSourceSD("/wav/update.wav");
break;
case 'o':
file = new AudioFileSourceSD("/wav/startup_dev.wav");
}
float volumeGain = ((float)bg1248_general_volume / 100.0) * 39.0;
Serial.print("volumeGain:");
Serial.println(volumeGain);
id3 = new AudioFileSourceID3(file);
out = new AudioOutputI2S(0, 0); // Output to builtInDAC
out->SetPinout(12, 0, 2);
out->SetOutputModeMono(true);
out->SetGain(volumeGain);
wav = new AudioGeneratorWAV();
wav->begin(id3, out);
However because I used the alphabet im going to run out of cases very very soon. I want to be able to call for a specific wav file anywhere in the project preferably like playWAV(filename) or something similar.
I call the function(file) like this (example condition)
if((ns->sensSgv<=cfg.snd_alarm) && (ns->sensSgv>=0.1)) {
// red alarm state
// M5.Lcd.fillRect(110, 220, 100, 20, TFT_RED);
Serial.println("ALARM LOW");
M5.Lcd.fillRect(0, 220, 320, 20, TFT_RED);
M5.Lcd.setTextColor(TFT_BLACK, TFT_RED);
int stw=M5.Lcd.textWidth(tmpStr);
M5.Lcd.drawString(tmpStr, 159-stw/2, 220, GFXFF);
if( (alarmDifSec>cfg.alarm_repeat*60) && (snoozeRemaining<=0) ) {
playWAV('a', 100);
'a'=case 100 = volume.
Alan, this is what I currently had in my enum, i was following a tutorial but doubt i did it right. even if i did i was getting errors saying i had duplicate cases when i don't.
EDIT:
The condition is set using this:
if((ns->sensSgv<=cfg.snd_alarm) && (ns->sensSgv>=0.1))
and if you notice at the bottom there is:
if( (alarmDifSec>cfg.alarm_repeat*60) && (snoozeRemaining<=0) ) {
playWAV('a', 100);
The a corelates to the case A in the switch case. shown above. currently all the places that use the playWAV function are manually specified.
My understanding was using the alphabets in switch case will ran out soon because of large no. of files (>26). So, I implemented the logic using enum first and below is the complete code.
#include<stdio.h>
enum soundEffects {
alarm,
alarm_high,
alarm_low,
Dev_startup,
error,
error1,
noread,
noreadings,
normalrange,
startup,
startup_dev,
update,
warning,
warning_high,
warning_low,
};
void playWav (enum soundEffects effect, int paci_volume)
{
//Serial.println("Entered paciplay_day");
//printf("Entered paciplay_day\n");
switch (effect)
{
case alarm:
//file = new AudioFileSourceSD("/wav/alarm.wav");
printf("/wav/alarm.wav\n");
break;
case alarm_high:
//file = new AudioFileSourceSD("/wav/alarmhigh.wav");
printf("/wav/alarmhigh.wav\n");
break;
case alarm_low:
//file = new AudioFileSourceSD("/wav/alarmlow.wav");
printf("/wav/alarmlow.wav\n");
break;
case error:
//file = new AudioFileSourceSD("/wav/error.wav");
printf("/wav/error.wav\n");
break;
case error1:
//file = new AudioFileSourceSD("/wav/error1.wav");
printf("/wav/error1.wav\n");
break;
case noread:
//file = new AudioFileSourceSD("/wav/noread.wav");
printf("/wav/noread.wav\n");
break;
case noreadings:
//file = new AudioFileSourceSD("/wav/noreadings.wav");
printf("/wav/noreadings.wav\n");
break;
case normalrange:
//file = new AudioFileSourceSD("/wav/normalrange.wav");
printf("/wav/normalrange.wav\n");
break;
case warning:
//file = new AudioFileSourceSD("/wav/warning.wav");
printf("/wav/warning.wav\n");
break;
case warning_high:
//file = new AudioFileSourceSD("/wav/warninghigh.wav");
printf("/wav/warninghigh.wav\n");
break;
case warning_low:
//file = new AudioFileSourceSD("/wav/warninglow.wav");
printf("/wav/warninglow.wav\n");
break;
case startup:
//file = new AudioFileSourceSD("/wav/startup.wav");
printf("/wav/startup.wav\n");
break;
case update:
//file = new AudioFileSourceSD("/wav/update.wav");
printf("/wav/update.wav\n");
break;
}
}
int main()
{
//below are the 3 ways of calling your playWav() function
//1 - using direct numbers
//this will throw compilation error when compiled using cpp compilers
for (int i = 0; i<14; i++)
{
printf("enum value: %d\n", i);
playWav(i, 50);
}
//2 - directly calling using the enum
playWav(startup, 100);
//3 - Just another way of calling
enum soundEffects sound;
sound = error;
playWav(sound, 100);
return 0;
}
Also, I implemented this same logic using double array's. Please do find it below. This uses the name of the file as a parameter so altogether we can eliminate the use of switch statement.
#include<stdio.h>
void playWav (const char *filename, int paci_volume)
{
//Serial.println("Entered paciplay_day");
printf("Entered paciplay_day\n");
//file = new AudioFileSourceSD("/wav/update.wav");
printf("/wav/%s\n", filename);
}
int main()
{
const char list_of_files[][25] = { "startup.wav", "update.wav", "warning.wav", "alarm.wav" };
for (int i = 0; i<4; i++)
{
printf("name: %s\n", list_of_files[i]);
playWav(list_of_files[i], 50);
}
return 0;
}
Please omit my printf statements which I used for debugging. I hope this is useful.
I have a small script that defines the casting time for all classes in this minor project im working on however i have a few issues.
I want to place a cap on the max value however i'm getting errors!
this is the function i was referring to.
void Player::ApplyRatingMod(CombatRating combatRating, int32 value, bool apply)
{
float oldRating = m_baseRatingValue[combatRating];
m_baseRatingValue[combatRating] += (apply ? value : -value);
// explicit affected values
float const multiplier = GetRatingMultiplier(combatRating);
float const oldVal = oldRating * multiplier;
float const newVal = m_baseRatingValue[combatRating] * multiplier;
switch (combatRating)
{
case CR_HASTE_MELEE:
ApplyAttackTimePercentMod(BASE_ATTACK, oldVal, false);
ApplyAttackTimePercentMod(OFF_ATTACK, oldVal, false);
ApplyAttackTimePercentMod(BASE_ATTACK, newVal, true);
ApplyAttackTimePercentMod(OFF_ATTACK, newVal, true);
break;
case CR_HASTE_RANGED:
ApplyAttackTimePercentMod(RANGED_ATTACK, oldVal, false);
ApplyAttackTimePercentMod(RANGED_ATTACK, newVal, true);
break;
case CR_HASTE_SPELL:
//ApplyCastTimePercentMod(oldVal, false);
//ApplyCastTimePercentMod(newVal, true);
break;
default:
break;
}
UpdateRating(combatRating);
}
void Player::UpdateRating(CombatRating cr)
{
int32 amount = m_baseRatingValue[cr];
// Apply bonus from SPELL_AURA_MOD_RATING_FROM_STAT
// stat used stored in miscValueB for this aura
AuraEffectList const& modRatingFromStat = GetAuraEffectsByType(SPELL_AURA_MOD_RATING_FROM_STAT);
for (AuraEffect const* aurEff : modRatingFromStat)
if (aurEff->GetMiscValue() & (1 << cr))
amount += int32(CalculatePct(GetStat(Stats(aurEff->GetMiscValueB())), aurEff->GetAmount()));
if (amount < 0)
amount = 0;
SetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + cr, uint32(amount));
bool affectStats = CanModifyStats();
switch (cr)
{
case CR_WEAPON_SKILL: // Implemented in Unit::RollMeleeOutcomeAgainst
case CR_DEFENSE_SKILL:
UpdateDefenseBonusesMod();
break;
case CR_DODGE:
UpdateDodgePercentage();
break;
case CR_PARRY:
UpdateParryPercentage();
break;
case CR_BLOCK:
UpdateBlockPercentage();
break;
case CR_HIT_MELEE:
UpdateMeleeHitChances();
break;
case CR_HIT_RANGED:
UpdateRangedHitChances();
break;
case CR_HIT_SPELL:
UpdateSpellHitChances();
break;
case CR_CRIT_MELEE:
if (affectStats)
{
UpdateCritPercentage(BASE_ATTACK);
UpdateCritPercentage(OFF_ATTACK);
}
break;
case CR_CRIT_RANGED:
if (affectStats)
UpdateCritPercentage(RANGED_ATTACK);
break;
case CR_CRIT_SPELL:
if (affectStats)
UpdateAllSpellCritChances();
break;
case CR_HIT_TAKEN_MELEE: // Implemented in Unit::MeleeMissChanceCalc
case CR_HIT_TAKEN_RANGED:
break;
case CR_HIT_TAKEN_SPELL: // Implemented in Unit::MagicSpellHitResult
break;
case CR_CRIT_TAKEN_MELEE: // Implemented in Unit::RollMeleeOutcomeAgainst (only for chance to crit)
case CR_CRIT_TAKEN_RANGED:
break;
case CR_CRIT_TAKEN_SPELL: // Implemented in Unit::SpellCriticalBonus (only for chance to crit)
break;
case CR_HASTE_MELEE: // Implemented in Player::ApplyRatingMod
case CR_HASTE_RANGED:
case CR_HASTE_SPELL:
break;
case CR_WEAPON_SKILL_MAINHAND: // Implemented in Unit::RollMeleeOutcomeAgainst
case CR_WEAPON_SKILL_OFFHAND:
case CR_WEAPON_SKILL_RANGED:
break;
case CR_EXPERTISE:
if (affectStats)
{
UpdateExpertise(BASE_ATTACK);
UpdateExpertise(OFF_ATTACK);
}
break;
case CR_ARMOR_PENETRATION:
if (affectStats)
UpdateArmorPenetration(amount);
break;
}
}
void Player::UpdateAllRatings()
{
for (uint8 cr = 0; cr < MAX_COMBAT_RATING; ++cr)
UpdateRating(CombatRating(cr));
}
You can notice how i want to cap the new value outcome to 32000.
Before it gets calculated to percentages!
I tried using
if(newVal > 32000)
newVal = 32000;
Which would normally do the job i guess, but i'm stuck with an error
E0137 expression must be a modifiable lvalue
On the line newVal = 32000;
Remove const qualifier from newVal
float newVal = m_baseRatingValue[combatRating] * multiplier;
You declare newVal as a constant (float const newVal = ...), so you're not allowed to assign a new value.
Removing const should work for you, e.g.
float newVal = m_baseRatingValue[combatRating] * multiplier;
if (newVal > 32000)
newVal = 32000;
...
In my STM32 code i have an
#define USART1 ((USART_TypeDef *) USART1_BASE)
and i would like to have
switch((uint32_t)ptr)
{
case USART1: return 1;
(...)
But gcc-arm (6.3.1) give me an error
error: reinterpret_cast from integer to pointer
I found an information that i can use
case __builtin_constant_p(USART1): return 0;
but this is only gcc solution? Is there something more generic?
There is UART1_BASE which is just the sum of a couple of unsigned integer constants. See the machine header:
#define PERIPH_BASE 0x40000000U
#define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000U)
#define USART1_BASE (APB2PERIPH_BASE + 0x1000U)
So should be able to use
switch((unsigned int)ptr) {
case USART1_BASE: return 1;
}
You forgot to cast pointer to integer in the case statement as well.
Example from my working code:
switch ((uint32_t)gpio) {
case (uint32_t)GPIOA:
EXTI_cfgr = 0b0000;
break;
case (uint32_t)GPIOB:
EXTI_cfgr = 0b0001;
break;
case (uint32_t)GPIOC:
EXTI_cfgr = 0b0010;
break;
default:
break;
}
USART1_BASE is a number in the header files of the STM32 development environment. You can compile your code when you decided what type shall be used in the switch. I recommend uint32_t:
switch((uint32_t)ptr)
{
case USART1_BASE: return 1;
(...)
If you like more readability you can try to remove the cast from the switch:
uint32_t ptr_value = (uint32_t)ptr;
switch(ptr_value)
{
case USART1_BASE: return 1;
(...)
Actually, the subject. I haven't found any standard way to convert GDI+ Status (error status returned by GDI+ methods) to string, something like FormatMessage()
If you want to convert labels in GDI+ Status into string, then the simplest thing you can do is this:
const char* StatusMsgMap[] =
{
"Ok", //StatusMsgMap[Ok] = "Ok";
"GenericError", //StatusMsgMap[GenericError] = "GenericError";
"InvalidParameter", //StatusMsgMap[InvalidParameter] = "InvalidParameter";
"OutOfMemory", //StatusMsgMap[OutOfMemory] = "OutOfMemory";
//so on
};
//Usage:
std::string error = StatusMsgMap[status]; // where status is Status type!
Or if you want more descriptive message, then this:
const char* StatusMsgMap[] =
{
"the method call was successful",
"there was an error on the method call, which is identified as something other than those defined by the other elements of this enumeration",
"one of the arguments passed to the method was not valid",
//so on
};
Since there are only 22 labels in the Status enum, creating a StatusMsgMap in the above way would not be much task, in my opinion. 5 minute is more than enough!
Here's something I wrote that uses hardcoded values.
std::string statusString(const Gdiplus::Status status) {
switch (status) {
case Gdiplus::Ok: return "Ok";
case Gdiplus::GenericError: return "GenericError";
case Gdiplus::InvalidParameter: return "InvalidParameter";
case Gdiplus::OutOfMemory: return "OutOfMemory";
case Gdiplus::ObjectBusy: return "ObjectBusy";
case Gdiplus::InsufficientBuffer: return "InsufficientBuffer";
case Gdiplus::NotImplemented: return "NotImplemented";
case Gdiplus::Win32Error: return "Win32Error";
case Gdiplus::Aborted: return "Aborted";
case Gdiplus::FileNotFound: return "FileNotFound";
case Gdiplus::ValueOverflow: return "ValueOverflow";
case Gdiplus::AccessDenied: return "AccessDenied";
case Gdiplus::UnknownImageFormat: return "UnknownImageFormat";
case Gdiplus::FontFamilyNotFound: return "FontFamilyNotFound";
case Gdiplus::FontStyleNotFound: return "FontStyleNotFound";
case Gdiplus::NotTrueTypeFont: return "NotTrueTypeFont";
case Gdiplus::UnsupportedGdiplusVersion: return "UnsupportedGdiplusVersion";
case Gdiplus::GdiplusNotInitialized: return "GdiplusNotInitialized";
case Gdiplus::PropertyNotFound: return "PropertyNotFound";
case Gdiplus::PropertyNotSupported: return "PropertyNotSupported";
default: return "Status Type Not Found.";
}
}
Use as follows:
const std::string statusMsg = statusString(theStatus);
//And then just output it.
std::cout << "Operation returned message: " << statusMsg << '\n';