I have an enum with one undefined and two user values:
class enum E
{
UNDEFINED,
VALUE1,
VALUE2
};
I want to add VALUE3 but I'm worried there's a lot of code like:
assert(val != E::UNDEFINED);
if(val == E::VALUE1)
{
}
else
{
// Without an assert this wrongly assumes E::VALUE2
}
and:
something = (val == E::VALUE1) ? a : b; // last part assumes E::VALUE2
I like that compilers warn against switch statements not handling all enumerations and wondered if there is anything similar to show all instances of the above?
I'm concerned I won't find and update all instances of the above.
Compiler is Clang
Enums are not restricted to the values you give names to. From cppreference (formatting is mine):
An enumeration is a distinct type whose value is restricted to a range of values (see below for details),
which may include several explicitly named constants ("enumerators"). The values of the constants are values of an integral type known as the underlying type of the enumeration.
The "below details" explain how the enums underlying type is determined. Out of this range we (usually) give names only to some values as in:
enum foo {A,B,C};
int main() {
foo x = static_cast<foo>(42);
}
This code is completely fine. x has an underlying value of 42. There is no name for the value but this doesn't really matter... unless you assume that it does.
That wrong assumption is made by this code:
assert(val != E::UNDEFINED);
if(val == E::VALUE1)
{
}
else
{
// Without an assert this wrongly assumes E::VALUE2
}
This code is what needs to be fixed (independent of whether you add a new named constant to the enum or not).
Now for a more serious trial to answer the question...
There is no way to get a warning when a chain of if-else does not cover all enum values. What you can do is to turn all if-else uses of the enum into errors. Consider what actually happens here:
if (x == E::VALUE1) do_something();
switch(x) {
case E::VALUE1 : return 1;
}
In the if statement we call operator==(foo,foo); its return value either is a bool or is implicitly converted to one. With the switch none of this is needed. We can make use of this to turn if-else usages of the enum into errors. Bear with me I will explain in two steps. First lets create a compiler error for if( x == E::VALUE1):
class helper {
operator bool(){ return false;}
};
helper operator==(E,E){
return {};
}
Now if (x == E::VALUE1) calls helper operator==(E,E), thats fine. Then the result is converted to bool, and that fails because the conversion is private. Using the enum in a switch is still ok and you can rely on compiler errors / warnings. The basic idea is just to have something that only fails to compile when called (in the wrong/right context). (Live Demo).
The drawback is that also all other used of operator== are broken. We can fix them by modifying the helper and the call sites:
#include <type_traits>
enum E {VALUE1};
struct helper {
bool value;
private:
operator bool(){ return false;}
};
helper operator==(E a,E b){
return {
static_cast<std::underlying_type_t<E>>(a) == static_cast<std::underlying_type_t<E>>(b)
};
}
int main() {
E x{VALUE1};
//if ( x== E::VALUE1); // ERROR
bool is_same = (x == E::VALUE1).value;
switch(x) {
case E::VALUE1 : return 1;
}
}
Yes it is a major inconvenience to have to write .value, but in this way you can turn all uses of the enum in ifs into errors while everything else will still compile. Also note that you have to make sure to cover all cases you want to catch (eg !=,<, etc).
Related
I wrote a function that requires two parameters, but I don't want those two parameters to be 0.
I want to make the compiler know that those two parameters cannot be 0 through some ways, otherwise the editor will report an error in the form of "red wavy line".
I refer to "custom exception class" to solve this problem, but I find this method does not work.
If there are someone knows how to do , I will be very happy, because it takes me a whole day
For example:
#include<iostream>
using namespace std;
int Fuction(int i , int j){
//code
}
int main(){
Funciton(1,1);
Funciton(0,0);
//I don't want i or j is zero
//But if they are still zero , The program will still work normally
return 0;
}
There is no integer type without a 0. However, you can provoke a compiler error by introducing a conversion to a pointer type. Its a bit hacky, but achieves what you want (I think) for a literal 0:
#include <iostream>
struct from_int {
int value;
from_int(int value) : value(value) {}
};
struct non_zero {
int value;
non_zero(int*) = delete;
non_zero(from_int f) : value(f.value) {}
};
void bar(non_zero n) {
int i = n.value; // cannot be 0
}
int main() {
bar(non_zero(42));
//bar(non_zero(0)); // compiler error
}
bar is the function that cannot be called with a 0 parameter. 0 can be converted to a pointer but that constructor has no definition. Any other int will pick the other constructor. Though it requires the caller to explicitly construct a non_zero because only one user defined conversion is taken into account.
Note that this only works for a literal 0. There is no error when you pass a 0 to this function:
void moo(int x){
bar(non_zero(x));
}
Thats why it should be considered as a hack. Though, in general it is not possible to trigger a compiler error based on the value of x which is only known at runtime.
If you want to throw an exception, thats a whole different story. You'd simply add a check in the function:
if (i == 0) throw my_custom_exception{"some error message"};
If you are using only MSVC you can also take a look at Structured Annotation Language (SAL). It is described on MSDN.
For your case you might be interested in _In_range_(lb,ub). An example would be:
void f(_In_range_(1,300) int a, _In_range_(1, 2147483647) int b);
Please note that this will not prohibit calling f(0, 0) but code analysis will trigger a warning. That warning will be triggered also in cases where you call f(x,x) and the compiler knows that x is zero.
In the past I liked to use SAL as it makes the interface clearer and can help reveal errors because the compiler can check more semantics. But now with modern C++ und the CppCoreGuidelines I am trying to follow the guidelines and so normally I don't need SAL anymore.
Found the following statement in Wiki:
C++11 introduced the concept of a constexpr-declared function; a
function which could be executed at compile time. Their return values
could be consumed by operations that require constant expressions,
such as an integer template argument. However, C++11 constexpr
functions could only contain a single expression that is returned (as
well as static_asserts and a small number of other declarations).
C++14 relaxes these restrictions. Constexpr-declared functions may now
contain the following: The conditional
...
branching statements if and switch
So, Is it actually possible to have a switch in a constexpr function in c++14/c++17? And, if possible, what syntax is for that?
For example, I'd like to have something like this:
enum class Terrain : std::uintmax_t {
ROAD,
SOIL,
GRASS,
MUD,
SNOW,
};
constexpr float
getStepPrice(Terrain const& terrain)
{
switch constexpr (terrain)
{
case Terrain::ROAD: return 1.0f;
...
}
}
Not exactly. In the case of if constexpr, you can rest assured that the resulting code has no branching. Moreover, discarded statements need not compile. Those are the guarantees I think you would expect from a true switch constexpr.
class Dog;
class Snake;
#define USE_IF
template<typename Pet>
constexpr void foo(Pet pet) {
#ifdef USE_IF
// This works
if constexpr(std::is_same_v<Pet, Dog>) pet.bark();
else pet.slither();
#else
// This doesn't
switch (std::is_same_v<Pet, Dog>) {
case true: pet.bark(); break; // <== Error if Snake
case false: pet.slither(); break; // <== Error if Dog
}
#else
}
BTW, I'm being a little nit-picky vis-a-vis Baum's accepted answer, which is fine, for practical puposes. I suspect you'd find good compilers will elide logically impossible bits from a switch-case statement with constexpr functions, as well as even non-constexpr inlined functions.
So, Is it actually possible to have a switch in a constexpr function in c++14/c++17?
Yes.
And, if possible, what syntax is for that?
There is absolutely nothing special about the syntax, it's just a normal switch. Like this:
constexpr int fun (int i) {
switch(i) {
case 0: return 7;
default: return 5;
}
}
int main () {
int arr[fun(3)];
}
I am getting the error "this cannot be used in a constant expression." What I am trying to do should be quite a simple task. All I would like to be able to do is use a variable declared in a class in a switch statement that is within a method in the class. For example:
In the class
private:
int someValue;
In the class constructor
Classname::ClassName(){
someValue = 1;
}
In the method
ClassName::someMethod(){
int command = getCommandNumber();
switch (command){
case someValue:
doSomeStuff();
break;
}
}
In the method if I replace someValue with just the number 1, everything works fine; however, if I use someValue, it won't compile, and it gives me the error stated above. How can I fix this?
The case labels in a switch-statement requires constants known at compile time. someValue must either be something of the same order with constexpr; or some prvalue constant; or an enum or enum class . If you must use a runtime criteria, use an if-else ladder.
ClassName::someMethod(){
int command = getCommandNumber();
if(command == someValue)
doSomeStuff();
else if(command == ...)
....
}
}
This is probably a really obvious question but I want to be sure about it before going on with my development.
I have a templated class something like:
template<TypeA var1, TypeB var2>
class myClass
{
//Attributes
...
//Methods
...
void checkHit(vector<Real>* path, vector<bool>* active)
{
for(int i = 0; i < N; i++)
{
//Some process
bool hit = ((var1 == Up) || (var1 == Down));
}
//...
bool flag = ((var2 == Left) || (var2 == Right));
}
}
If I create and object like
myClass obj<Up, Right>(...);
When executing the method
obj.checkHit( ... );
Will the program just check for bool hit = ((var1 == Up) and (var2 == Right) ?? In other words, will the compiler throw away the code that doesn't has to do with the template-parameters passed? What I mean is if the resulting code after compiling will be something like
template<TypeA var1, TypeB var2>
class myClass
{
//Attributes
...
//Methods
...
void checkHit(vector<Real>* path, vector<bool>* active)
{
for(int i = 0; i < N; i++)
{
//Some process
bool hit = ((var1 == Up)); //Like if I have never put "|| (var1 == Down));"
}
//...
bool flag = ((var2 == Right));
}
}
Hope the example is clear enough, I just simplified (a lot) the real code but it should be roughly equivalent. If it isn't clear just tell and I will gladly improve it.
I'm assuming your TypeA and TypeB are either enumerations or some sort of class/struct with those values defined?
That being the case, the compiler isn't going to "throw out" code here. Your conditional checks to see what the template parameters are, so if they don't match what is in the conditionals, you'll end up with a call that would basically do this:
bool hit = (0 == 1 || 1 == 2);
Depending on your optimization settings, the compiler may realize that this will always be false and just set it to false (also assuming you do something useful in the function so the compiler doesn't just turn it into a noop).
You also should pass your vectors by reference (or constant reference), and I would avoid using vector<bool>.
The example is not really clear enough, there is no "code that doesn't has to do with the template-parameters passed" because nothing depends on hit or flag, so a decent optimizer would turn checkHit into a completely empty function!
The compiler can evaluate the ((var1 == TypeA::Up) || (var2 == TypeB::Down)) condition at compile-time and a decent optimizing compiler will propagate the result of that condition to the rest of the function, removing any dead code that will never be run due due to the value of that condition.
Also, do you really want to pass these arguments by value?
void checkHit(vector<Real> path, vector<bool> active)
the Program will NOT throw away any part of the code.Template classes are only used to generalize the usage of a class .once a typeA and Type B are chosen they will all be taken as the Type A and Type B throughout the code and the rest of the code will execute in the normal way that it would without any templates
I've recently been doing a huge refactoring where I was changing a lot of my code to return booleans instead of an explicit return code. To aid this refactoring I decided to lean on the compiler where possible by getting it to tell me the places where my code needed to be changed. I did this by introducing the following class (see here for the lowdown on how this works):
///
/// Typesafe boolean class
///
class TypesafeBool
{
private:
bool m_bValue;
struct Bool_ {
int m_nValue;
};
typedef int Bool_::* bool_;
inline bool_ True() const { return &Bool_::m_nValue; }
inline bool_ False() const { return 0; }
public:
TypesafeBool( const bool bValue ) : m_bValue( bValue ){}
operator bool_() const { return m_bValue ? True() : False(); }
};
Now, instead of using a normal bool type as the return type, I used this class which meant that I couldn't compile something like this any more:
TypesafeBool SomeFunction();
long result = SomeFunction(); // error
Great: it has made the refactoring manageable on a huge codebase by letting the compiler do a lot of the hard work for me. So now I've finished my refactoring and I'd quite like to keep this class hanging around and carry on using it since it affords us an extra level of safety that the built-in bool type doesn't.
There is however one "problem" which is preventing me from doing this. At the moment we make heavy use of the ternary operator in our code, and the problem is that it is not compatible with this new class without explicit casts:
TypesafeBool result = ( 1 == 2 ? SomeFunction() : false ); // error: different types used
TypesafeBool result = ( 1 == 2 ? SomeFunction() : (TypesafeBool)false );
If I could "solve" this issue so that I could use my class in a seamless manner I would probably carry on using it throughout the codebase. Does anyone know of a solution to this issue? Or is it just impossible to do what I want?
In the context of the conditional operator, the type of the expression is the common type of the last two operands. The complete rules to determine this common type are a bit complex, but your case happens to be trivial: if one of the two possible return values is a class type, the other value must have the same class and the common type is obviously also that class.
That means that if one of the operands is a TypesafeBool, then the other must be as well.
Now the problem you're really trying to solve has been solved before. The trick is not providing a class; instead use a typedef. See for instance safe bool.
class CCastableToBool
{
public:
// ...
operator bool() const
{
//...
{
return true;
}
//...
return false;
}
private:
// ...
};
but beware, in C++ it is considered really dangerous to have a class that can be casted to bool. You are warned :-)
you can read this there, SafeBool
You should explicitely call TypesafeBool::True() in all your ternary tests.
TypesafeBool result = ( 1 == 2 ? SomeFunction().True() : false );
I don't know about a seamless manner, the ternary operator has some restrictions on its use...
However, why don't you define two constants ?
TypesafeBool const True = TypesafeBool(true);
TypesafeBool const False = TypesafeBool(false);
And then:
TypesafeBool result = ( 1 == 2 ? SomeFunction() : False );
Of course, it's a bit unorthodox since I play on the capitalization to avoid reusing a reserved word :)
Is it a possibility to make the constructor of TypesafeBool explicit? Of course, now the usage has to be
TypesafeBool result( 1 == 2 ? b : false );
Could you use an assignment operator that takes in a bool as the external argument, as well as one that takes a TypesafeBool? It might be something to try out...
Nice try, but if your code base is large, you are probably better off using a static checker such as PC-Lint to look for implicit bool<->int conversions instead.