Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a C++ function be declared such that the return value cannot be ignored?

I'm trying to determine whether a C++ function can be declared in such a way that the return value cannot be ignored (ideally detected at compile time). I tried to declare a class with a private (or in C++11, deleted) operator void() to try to catch the implicit conversion to void when a return value is unused.

Here's an example program:

class Unignorable {     operator void(); };  Unignorable foo() {     return Unignorable(); }  int main() {     foo();     return 0; } 

Unfortunately, my compiler (clang-703.0.31) says:

test.cpp:2:5: warning: conversion function converting 'Unignorable' to 'void' will never be used     operator void();     ^ 

and doesn't raise any error or warning on the call to foo(). So, that won't work. Is there any other way to do this? Answers specific to C++11 or C++14 or later would be fine.

like image 426
Greg Hewgill Avatar asked Sep 05 '16 08:09

Greg Hewgill


People also ask

How do you declare a function that does not return a value?

Void functions are created and used just like value-returning functions except they do not return a value after the function executes. In lieu of a data type, void functions use the keyword "void." A void function performs a task, and then control returns back to the caller--but, it does not return a value.

Does function always return a value in C?

The C standard does not say a function must return a value or that, if it does not, the behavior is undefined. If the value is used by the caller, then the behavior is undefined, because C 2018 6.9.

What a function Cannot return in C?

A function that returns void means it does not return a value at all. C does not allow you to use the return statement with an expression (even if it is a void one) if your function is declared as void .


1 Answers

To summarize from other answers & comments, basically you have 3 choices:

  1. Get C++17 to be able to use [[nodiscard]]
  2. In g++ (also clang++), use compiler extensions like __wur (defined as __attribute__ ((__warn_unused_result__))), or the more portable (C++11 and up only) [[gnu::warn_unused_result]] attribute.
  3. Use runtime checks to catch the problem during unit testing

If all of these 3 are not possible, then there is one more way, which is kind of "Negative compiling". Define your Unignorable as below:

struct Unignorable {   Unignorable () = default; #ifdef NEGATIVE_COMPILE   Unignorable (const Unignorable&) = delete;  // C++11   Unignorable& operator= (const Unignorable&) = delete;   //private: Unignorable (const Unignorable&); public:  // C++03   //private: Unignorable& operator= (const Unignorable&); public: // C++03   /* similar thing for move-constructor if needed */ #endif }; 

Now compile with -DNEGATIVE_COMPILE or equivalent in other compilers like MSVC. It will give errors at wherever the result is Not ignored:

auto x = foo();  // error 

However, it will not give any error wherever the result is ignored:

foo(); // no error 

Using any modern code browser (like eclipse-cdt), you may find all the occurrences of foo() and fix those places which didn't give error. In the new compilation, simply remove the pre-defined macro for "NEGATIVE_COMPILE".

This might be bit better compared to simply finding foo() and checking for its return, because there might be many functions like foo() where you may not want to ignore the return value.

This is bit tedious, but will work for all the versions of C++ with all the compilers.

like image 67
iammilind Avatar answered Sep 22 '22 18:09

iammilind