Switch in constexpr function - c++

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)];
}

Related

Adding a new enum without breaking existing code

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).

Implicitly cast parameter to bool

Premise:
I am trying to make a Define scope that is not implemented using a macro because of the potential issues with macros. Here is my initial attempt
//version for if not defined
bool Defined()
{
return false
}
//version for if defined
bool Defined(bool anything)
{
return true;
}
And an example use case
if(Defined(_DEBUG))
{
Stuff...
}
which would replace
#ifdef _DEBUG
Stuff...
#endif
or
#define Defined() false
#define Defined(Anything) true
Benefits:
syntax is cleaner, it is scoped,
This code is not conditional, so the compiler will be able to easily optimize code sections out.
Issues
There are a few issues with this procedure, the first is the reason for this post.
Question:
You can't pass in anything that is not implicitly cast-able to a bool. Is there a way to implicitly cast any object, number, pointer, etc to a bool? I don't believe there is, but I wanted to make sure, before I continued.
You can use a generic template:
template<class T>
bool Defined(T &&) { return true; }

Why doesn't gcc detect all enum vals handled?

I have some c++ code where I switch over values in an enum. I was trying to compile this with -Wall -Wextra -Werror. This is fine when using clang. GCC, however, complains that the default code path is not covered. A simplified version looks as follows:
enum class Types: int {
A,
B,
C
};
bool some_logic(Types val) {
switch (val) {
case Types::A:
return (false);
case Types::B:
return (true);
case Types::C:
return (false);
}
}
I can handle this by adding a default case, or another return statement at the end of the function. However, my question was why doesn't GCC detect that all of the cases of the enum are covered? Or phrased differently, is there a legitimate reason for GCC to complain here?
I've put a comparison of the compiler outputs here.
Because all the cases aren't covered.
It is possible to assign to val a value that is not named in the Types definition. Enums aren't constrained to just those values.
some_logic((Types)3); // whoops
If you're really, properly sure that some_logic will only be provided a value that you named in the Types definition, or wish to consider other cases to be "exceptional" precondition violations, that's fine but you'll still need to tell the computer that.
Opinion varies on the best approach, but in this case I'd leave out the default (so that you still get compiler warnings if you later add to Types and forget to update the switch) but plonk a simple throw afterwards:
bool some_logic(const Types val)
{
switch (val) {
case Types::A:
return (false);
case Types::B:
return (true);
case Types::C:
return (false);
}
throw std::runtime_error("Didn't expect that innit");
}
in the absence of any stronger requirements.

Is it possible to ignore [[nodiscard]] in a special case?

C++17 has a new attribute, [[nodiscard]].
Suppose, that I have a Result struct, which has this attribute:
struct [[nodiscard]] Result {
};
Now, if I call a function which returns Result, I got a warning if I don't check the returned Result:
Result someFunction();
int main() {
someFunction(); // warning here, as I don't check someFunction's return value
}
This program generates:
warning: ignoring return value of function declared with 'nodiscard'
attribute [-Wunused-result]
So far, so good. Now suppose, that I have a special function, for which I still want to return Result, but I don't want this warning generated, if the check is omitted:
Result someNonCriticalFunction();
int main() {
someNonCriticalFunction(); // I don't want to generate a warning here
}
It is because, someNonCriticalFunction() does something non-critical (for example, something like printf - I bet that no-one checks printf's return value all the time); most cases, I don't care if it fails. But I still want it to return Result, as in some rare cases, I do need its Result.
Is it possible to do this somehow?
Possible solutions which I don't like:
I would not like calling it as (void)someNonCriticalFunction(), because this function is called a lot of times, it is awkward
creating a wrapper around someNonCriticalFunction(), which calls (void)someNonCriticalFunction(): I don't want to have a differently named function just because of this
removing [[nodiscard]] from Result, and add it to every function which returns Result
Why not make use of std::ignore from the <tuple> header—that would make the discard explicit:
[[nodiscard]] int MyFunction() { return 42; }
int main()
{
std::ignore = MyFunction();
return 0;
}
Compiler explorer of this code snippet: https://godbolt.org/z/eGPsjajz8
CPP Reference for std::ignore: https://en.cppreference.com/w/cpp/utility/tuple/ignore
I recommend the option you ruled out:
"removing [[nodiscard]] from Result, and add it to every function which returns Result."
But since you don't seem happy with it, here's another solution, using bog-standard inheritance:
struct [[nodiscard]] Result {
};
struct DiscardableResult: public Result {
};
For the functions where you can discard the result, use DiscardableResult as return type:
Result func1();
DiscardableResult func2();
func1(); // will warn
func2(); // will not warn
They say that every problem in computer science can be solved by adding another layer of indirection:
template <bool nodiscard=true>
struct Result;
template <>
struct Result<false> {
// the actual implementation
};
template <>
struct [[nodiscard]] Result<true>
: Result<false>
{
using Result<false>::Result;
};
This is effectively making Result conditionally [[nodiscard]], which allows:
Result<true> someFunction();
Result<false> someNonCriticalFunction();
int main() {
someFunction(); // warning here
someNonCriticalFunction(); // no warning here
}
Although really, this is identical to:
removing [[nodiscard]] from Result, and add it to every function which returns Result
which gets my vote to begin with.
You can suppress the warning with another C++17 attribute, namely [[maybe_unused]]
[[nodiscard]] int MyFunction() { return 42; }
int main()
{
[[maybe_unused]] auto v = MyFunction();
return 0;
}
This way you also avoid the confusing dependency to std::tuple which comes with std::ignore, even CppCoreGuidelines is openly recommending to use std::ignore for ignoring [[nodiscard]] values:
Never cast to (void) to ignore a [[nodiscard]]return value. If you
deliberately want to discard such a result, first think hard about
whether that is really a good idea (there is usually a good reason the
author of the function or of the return type used [[nodiscard]] in the
first place). If you still think it's appropriate and your code
reviewer agrees, use std::ignore = to turn off the warning which is
simple, portable, and easy to grep.
Looking at C++ reference, officially std::ignore is only specified to be used in std::tie when unpacking tuples.
While the behavior of std::ignore outside of std::tie is not formally
specified, some code guides recommend using std::ignore to avoid
warnings from unused return values of [[nodiscard]] functions.
cast the result to a (void *).
int main()
{
(void *)someFunction(); //Warning will be gone.
}
This way you "used" your result as far as the compiler is concerned. Great for when you are using a library where nodiscard has been used and you really don't care to know the result.

Using C++ lambda functions during variable initialisation

I think many of you have this kind of code somewhere:
int foo;
switch (bar) {
case SOMETHING: foo = 5; break;
case STHNELSE: foo = 10; break;
...
}
But this code has some drawbacks:
You can easily forget a "break"
The foo variable is not const while it should be
It's just not beautiful
So I started wondering if there was a way to "improve" this kind of code, and I got this little idea:
const int foo = [&]() -> int {
switch (bar) {
case SOMETHING: return 5;
case STHNELSE: return 10;
...
}
}();
Note: the first pair of parentheses it not mandatory, but MSVC++ doesn't support this yet
You can use the same trick with if-else where the ternary operator would be too complicated, variables that require to be passed by pointers to be initialized (like for DirectX functions), etc.
My questions are:
Is there anything wrong with this code that I didn't see?
Do you find it better than the one above?
g++ seems to inline the function, but do you think that all compilers will do so?
EDIT: this is what I mean by "DirectX functions"
_xAudio2 = [&]() -> std::shared_ptr<IXAudio2> {
IXAudio2* ptr = nullptr;
if (FAILED(XAudio2Create(&ptr, xAudioFlags, XAUDIO2_DEFAULT_PROCESSOR)))
throw std::runtime_error("XAudio2Create failed");
return std::shared_ptr<IXAudio2>(ptr, [](IUnknown* ptr) { ptr->Release(); });
}();
This is a fairly common technique in other languages. Almost every high-level feature of Scheme is defined in terms of lambdas that are immediately called.
In JavaScript it is the basis of the "module pattern", e.g.
var myModule = (function() {
// declare variables and functions (which will be "private")
return {
// populate this object literal with "public" functions
};
})();
So an anonymous function is declared and immediately called, so that any internal details are hidden and only the return value is exposed externally.
The only downsides is that on a casual reading of the code, the return statements will appear to be returning from the outer function (there was intense controversy about this during the Java lambda wars). But this is just something you have to get used to once your language has lambdas.
There are many language features in an imperative language like C++ which would benefit from being able to return a value (rather than being like a void function). For example, if has an alternative, the tertiary operator expr ? a : b.
In Ruby pretty much all statements can be evaluated, so there is no need for a separate syntax where a return value can be supplied. If C++ worked that way, this would mean things like:
auto result = try
{
getIntegerSomehow();
}
catch (const SomeException &)
{
0;
}
I don't see any reason at all to use a switch case in such a case. Any decent compiler will generate just as fast code with if statements as with a switch case.
if(bar == SOMETHING)
foo = 5;
else if(bar == STHNELSE)
foo = 10;