Cppcoreguidelines: ES.48: alternative to (void) cast

Created on 3 Mar 2020  路  12Comments  路  Source: isocpp/CppCoreGuidelines

As an alternative to (void) cast or static_cast<void>() I suggest using a (empty) function "discard" to intentionally discard a [[nodiscard]] value:

`template
void discard(const T&) {}

[[nodiscard]] int foo () {return 0;}

int main () {
(void) foo();
static_cast<void>(foo());
discard(foo());
}`

This avoids a cast and is more readable.

All 12 comments

Why? Imho that makes the code just harder to parse by humans due to the additional parenthesis around the expression, maybe even harder to optimize by the compiler and also more difficult to step through in debug builds. Also, in which namespace and header would discard live (i.e. it is not just discard(foo()), but gsl::discard(foo()) and an extra dependency)?

Casting to void via (void) is a well established and concise pattern, that might not be obvious on first contact, but it is something you pick up once an essentially never forget it again. In particular, anyone who sees gsl::discard for the first time would probably also have to look up, what exactly it does (although of course you can make an educated guess).

On a somewhat recent reddit thread someone commented using something like this:

[[nodiscard]] int f();

void g()
{
    [[maybe_unused]] f();
}

That's another alternative.

This seems to be the remaining case for c-style casts as called out under enforcement of this rule.

Force the elimination of C-style casts, except on a function with a [[nodiscard]] return.

ES.49, also on the subject of casts does not mention this. It would be a win to get rid of this exception but I agree the convention has a lot of momentum.

Regarding these comments

it is something you pick up once an essentially never forget it again

the convention has a lot of momentum

I wonder if this is true. Personally I've never encountered this in live code. I must have encountered this when I last read through the core guidelines but when this issue was raised I was completely surprised (i.e. I did forget it). This is just anecdotal evidence but I wonder if a decision is being made based on a perceived trend by a handful of experts rather than actual data. In general I would trust this handful of experts when they tell me what code _should_ look like but can anyone say what most code _does_ look like?

I'm second guessing my momentum comment; my experience is colored by over-eager use of (void) prior to [[nodiscard]], I always asked for a comment instead. I also recall using static_cast<void> to avoid the c-style cast.

I also realize that my cases were in very strange cases, test code, lifetime transfer between type systems. very rare.

On a somewhat recent reddit thread someone commented using something like this:

[[nodiscard]] int f();

void g()
{
    [[maybe_unused]] f();
}

That's another alternative.

This doesn't compile for me in msvc 2017 with /std:c++17. It also doesn't seem to match any of the cases in https://en.cppreference.com/w/cpp/language/attributes/maybe_unused . Did you mean something like
[[maybe_unused]] auto x = f();

I just tested it out at https://godbolt.org/z/ngAtzV and GCC accepts it but still warns. Maybe it worked for the redditor's environment.

The more I think about it the more [[maybe_unused]] f(); seems like the ideal solution. It's an existing mechanism used in a subtly different context to mean the same thing it means in all its other contexts.

To someone not used to it, such as myself, casting to void to defeat [[nodiscard]] just seems so weird. To me this seems so unlike the purpose of any other cast. The fact that ES.48 requires a paragraph documenting it as an exception to the recommendation on casts demonstrates this in my opinion.

Unfortunately it's too late to complain about the lack of [[maybe_unused]] f(); now but is void cast the best alternative to recommend? It seems to me that [[maybe_unused]] auto&& x = f(); makes the intention clearer than void cast and almost as clear as [[maybe_unused]] f();. Downsides are the && (which I think are required for a generic solution without redundant copying) and the variable name which is redundant in most contexts (code review discussions and compiler diagnostics excepted?).

When making the argument that this complication makes ES.48 more complicated than it should have to be it's interesting to examine the Enforcement advice "Force the elimination of C-style casts, except on a function with a [[nodiscard]] return.". As written, that rule would permit the code

[[nodiscard]] getX() { return INT_MAX; }
float x = (float)getX();

which I don't believe is the intention. I suspect the impact of that subtle wording error is likely to be minor but I think it acts to illustrate the point that the rule might be too complex.

[[maybe_unused]] auto&& x = f();

It also has the disadvantage that the lifetime of the value returned from f() gets extended and it is much more verbose. Maybe someone can write a paper to allow [[maybe_unused]] f().

"Force the elimination of C-style casts, except on a function with a [[nodiscard]] return.". As written, that rule would permit the code

[[nodiscard]] getX() { return INT_MAX; }
float x = (float)getMyInt();

which I don't believe is the intention.

That should indeed get fixed.

That's a good point about lifetime extension. That's a sufficiently good reason not to advocate that approach universally I think.

Presumably as someone who doesn't attend the c++ committee meetings I'm not in a position to write such a paper?

I'll make a pull request to correct the enforcement. EDIT: pull request here #1588

Editors call: The commenters have addressed the original question, and a PR has been merged. Thanks!

In my opinion #1685 solves the original issue (though by a different mechanism)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

TomMettam picture TomMettam  路  3Comments

jonnygrant picture jonnygrant  路  3Comments

tamaskenez picture tamaskenez  路  6Comments

jeffreylindsey picture jeffreylindsey  路  5Comments

galik picture galik  路  3Comments