Is there a C++ equivalent of the variable discard ‘_’ in C#?

In C#, there’s a convenient feature using the underscore _ as a discard variable when one wants to explicitly ignore the result of an operation.

I’m currently looking for an equivalent feature or workaround in C++ that would allow me to discard specific values or save memory allocation when retrieving multiple values from a function.

Example:

Let’s say I have a function like this:

void readValues(float& temperature, float& humidity, float& dewpoint, float& tempTrend, float& humTrend) {
    // Some operation to retrieve values
}

If I only need to know the temperature, and I do not have a temperature-specific function, how can I discard the other values in the most memory-efficient way?

Or any other approach that could help in conserving memory space when ignoring certain return values from functions in an Arduino/ESP32 environment?

What I’m doing now:

float temperature;
float discard;

readValues(temperature, discard, discard, discard, discard);

What I tried:

float temperature;
readValeus(temperature, null_ptr, null_ptr, null_ptr, null_ptr);
float temperature;
readValues(temperature, 0, 0, 0, 0);

Thank you for any insights or suggestions!

  • I recommend avoiding out parameters, instead use return values.

    – 

There are a few ways to do what you want.
There is no direct equivalent to the discard keyword though.

Firstly, I wouldn’t worry about being memory-efficient in this case.
Even if you always returned all values, unused values and their creation may be optimized away.

Also, output parameters are typically frowned upon in C++. (see F.20: For “out” output values, prefer return values to output parameters) You can pack things into a struct and then simply use the parts of it that you’re interested in. Anyhow, here are some possible solutions:

(1) Function overloading

void readValues(float& temperature, float& humidity, float& dewpoint);
void readValues(float& temperature, float& humidity);

The second overload makes dewpoint effectively an optional parameter.

(2) Pointers and default parameters

void readValues(float& temperature, float& humidity, float* dewpoint = nullptr);
// ...
readValues(t, h);     // don't provide dewpoint
readValues(t, h, &d); // provide dewpoint

(3) Avoid output parameters

This is my personal favorite.

struct Weather {
    float temperature;
    float humidity;
    float dewpoint;
};

Weather readValues();

// ...
Weather w = readValues();
auto [t, h, d] = readValues();
auto [t, h, _] = readValues();

(4) [[maybe_unused]]

void readValues(float& temperature, float& humidity, float& dewpoint);
// ...

float t, h;
[[maybe_unused]] float _;
readValues(t, h, _);

You still have to provide an extra argument, but [[maybe_unused]] expresses intent clearly and suppresses warnings about unused variables, if any.

It is trivial to implement some sort of _ surrogate providing object to store output value and doing nothing with it.

void readValues(float& temperature, float& humidity, float& dewpoint, float& tempTrend, int& counter) {
    // Some operation to retrieve values
}

class t_Discarder final
{
    public: template<typename x_Object>
    /* IMPLICIT */ operator x_Object &(void) const
    {
        static x_Object s_object{};
        return s_object;
    }
};

t_Discarder _{};

int main()
{
    float temperature{};
    readValues(temperature, _, _, _, _);
}

online compiler

However is it certainly not a good practice. In production code it would be better to supply properly named arguments and to explicitly mark them as unused or to invent a better query interface that does not require supplying so many arguments every time with most of them being discarded.

Leave a Comment