I know that you can use static_cast<void>
, but it just seems too verbose for me, and not reflecting the original intent that I want to discard a return value, not to cast it to anything.
Recently I stumbled upon std::ignore
, which can accept a value of any type, the name is clear and readable, and to me it seems fitting.
I know that the initial intent was to use std::ignore
alongside with std::tie
to discard any unwanted values, but I guess the original intent of static_cast
was to actually cast values for some better reasons than discarding values so the compiler won’t complain.
So, is it OK to use std::ignore
for the purpose I described in the question?
For example:
std::ignore = std::transform(...);
12
2 Answers
Yes, it is okay. In fact, it is considered much better style by some people.
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, usestd::ignore =
to turn off the warning which is simple, portable, and easy to grep.
– CppCoreGuidelines ES.48: Avoid casts
An argument against it is that std::ignore
is only defined in terms of its effect in std::tie
:
template<class... TTypes> constexpr tuple<TTypes&...> tie(TTypes&... t) noexcept;
Returns:
tuple<TTypes&...>(t...)
. When an argument int
isignore
, assigning any value to the corresponding tuple element has no effect.
This is mostly a philosophical issue though. std::ignore
is implemented in such a way that you can do std::ignore = ...
on its own in every major standard library, and may soon be well-defined. See P2968: Make std::ignore
a first-class object.
In the end, it’s stylistic preference. You can use (void)
, static_cast<void>
, or std::ignore
. They are all acceptable, and which one to use is a matter of opinion.
What matters is that you use a consistent style throughout your project, i.e. if you use std::ignore
to discard results in one place, use it everywhere.
3
-
"Never cast to
(void)
to ignore a[[nodiscard]]
return value." Erm, why? Because God said so? There's no rationale given. Ignore that advice.– user5416864 hours ago
-
@user541686 The point of "nodiscard" is that the caller is supposed to check the result. Not checking the result is normally a bug, hence the compiler warning. Any mechanism to tell future maintainers that you did intend that (and best practise, comments explaining why) would do, and casting to void has 40 years of history for doing this; but people may prefer the newer method. It's only about setting a consistent house style at that point.
– Graham3 hours ago
-
@Graham: "The point of
nodiscard
is that the caller is supposed to check the result." Yes… we all understand that. That obviously wasn't the point of my comment. "Casting tovoid
has 40 years of history for doing this" which is closer to the point I was making. "But people may prefer the newer method" … but why the newer method?! was the question. The page gives absolutely no reason whatsoever. Which makes for terrible advice; just toss it into the firepit.– user5416862 hours ago
In theory, std::ignore
‘s operator=
could be implemented as:
[[nodiscard]] auto& operator=(auto&&...) const { return *this; }
So instead of suppressing compiler warnings, assigning to std::ignore
could cause a warning.
And std::tuple
‘s operator=
could do something like this, to suppress the warning when std::ignore
is part of a tuple
:
(static_cast<void>(std::get<I>(*this) = std::get<I>(rhs)), ...);
In practice, no implementation do this.
Whether it is OK to use std::ignore =
depends on whether you want to rely on the fact that no implementation uses [[nodiscard]]
in the definition of std::ignore
. I, personally, would rather not rely on this undocumented fact.
As far as I know
std::ignore
is only defined in terms of its use instd::tie
. Strictly speaking, I think it would have to bestd::tie(std::ignore) = std::tie(std::transform(...));
.14 hours ago
Your usage looks valid. @FrançoisAndrieux see here – the first example is not related to
std::tie
(std::ignore = dontIgnoreMe();
).14 hours ago
Regarding using
static_cast<void>
, this is one case where it is generally harmless to use an explicit conversion tovoid
like(void)my_function();
. Nobody can use the result, by definition, which eliminates most of the risks related to using them. And it is a relatively well known convention, so shouldn't act as a red flag or cause for confusion or concern.14 hours ago
BTW,
std::transform
doesn't return a[[nodiscard]]
. sostd::ignore =
can even be removed :-), no warnings expected (else we would prefix any expression by it asstd::ignore = std::cout << "hello"
🙂 ).14 hours ago
// my_lint_tool_ignore_flag
might be an alternative too. (or maybe the warning is more subtle that just ignoring the return value).13 hours ago