valores una todas tipos retornan que llamar lenguaje las funciones funcion ejemplos como c++ return-value void

c++ - una - tipos de funciones en lenguaje c



¿Se puede declarar una función de C++ de tal manera que no se pueda ignorar el valor de retorno? (3)

Antes de c ++ 17, este enfoque vino a la mente:

#include <stdexcept> #include <exception> #include <boost/optional.hpp> // proxy object which complains if it still owns the return // value when destroyed template<class T> struct angry { angry(T t) : value_(std::move(t)) {} angry(angry&&) = default; angry(angry const&) = default; angry& operator=(angry&&) = default; angry& operator=(angry const&) = default; ~angry() noexcept(false) { if (value_) throw std::logic_error("not used"); } T get() && { T result = std::move(value_).value(); value_.reset(); return result; } boost::optional<T> value_; }; // a function which generates an angry int angry<int> foo() { return 10; } int main() { // obtain an int auto a = foo().get(); // this will throw foo(); }

Sinopsis: en lugar de devolver una T, una función devuelve una angry<T> que castigará al interlocutor lanzando un logic_error si el valor no se extrae antes de la destrucción.

Es una solución en tiempo de ejecución, que es una limitación, pero al menos debería detectarse al principio de las pruebas unitarias.

Un usuario astuto puede, por supuesto, subvertirlo:

foo().get(); // won''t throw

Estoy tratando de determinar si una función de C ++ puede ser declarada de tal manera que el valor de retorno no pueda ser ignorado (idealmente detectado en tiempo de compilación). Intenté declarar una clase con un operator void() private (o en C ++ 11, delete d) operator void() para intentar capturar la conversión implícita a void cuando no se usa un valor de retorno.

Aquí hay un programa de ejemplo:

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

Desafortunadamente, mi compilador (clang-703.0.31) dice:

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

y no genera ningún error o advertencia en la llamada a foo() . Entonces, eso no funcionará. Hay alguna otra manera de hacer esto? Las respuestas específicas a C ++ 11 o C ++ 14 o posterior estarán bien.


Consulte __attribute__ ((warn_unused_result)) .

int foo() __attribute__ ((warn_unused_result)); int foo(){return 123;} int main() { foo(); //compiler warning auto i = foo(); //valid }

Luego obliga a que la advertencia sea un error:

clang++ -std=c++1z -Werror="unused-result"


Para resumir de otras respuestas y comentarios, básicamente tiene 3 opciones:

  1. Obtén C ++ 17 para poder usar [[nodiscard]]
  2. En g ++ (también clang ++), use extensiones de compilador como __wur (definida como __attribute__ ((__warn_unused_result__)) ), o el atributo más portátil (solo C ++ 11 y superior) [[gnu::warn_unused_result]] .
  3. Utilice los controles de tiempo de ejecución para detectar el problema durante las pruebas unitarias.

Si todos estos 3 no son posibles, entonces hay una manera más, que es una especie de "compilación negativa" . Define tu Unignorable como abajo:

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

Ahora compile con -DNEGATIVE_COMPILE o equivalente en otros compiladores como MSVC. Dará errores donde el resultado no se ignora :

auto x = foo(); // error

Sin embargo, no dará ningún error donde se ignore el resultado:

foo(); // no error

Usando cualquier navegador de código moderno (como eclipse-cdt), puedes encontrar todas las apariciones de foo() y corregir esos lugares que no dieron error. En la nueva compilación, simplemente elimine la macro predefinida para "NEGATIVE_COMPILE".

Esto podría ser un poco mejor en comparación con simplemente encontrar foo() y verificar su retorno, ya que puede haber muchas funciones como foo() donde es posible que no quiera ignorar el valor de retorno.

Esto es un poco tedioso, pero funcionará para todas las versiones de C ++ con todos los compiladores.