Can a C++;函数是否声明为不能忽略返回值? 我试图确定C++函数是否可以以这样的方式声明:返回值不能被忽略(在编译时理想地检测到)。我试图用private(或者在C++11中,deleted)操作符void()声明一个类,以便在返回值未使用时捕获到对void的隐式转换

Can a C++;函数是否声明为不能忽略返回值? 我试图确定C++函数是否可以以这样的方式声明:返回值不能被忽略(在编译时理想地检测到)。我试图用private(或者在C++11中,deleted)操作符void()声明一个类,以便在返回值未使用时捕获到对void的隐式转换,c++,return-value,void,C++,Return Value,Void,下面是一个示例程序: class Unignorable { operator void(); }; Unignorable foo() { return Unignorable(); } int main() { foo(); return 0; } 不幸的是,我的编译器(clang-703.0.31)说: 并且不会在调用foo()时引发任何错误或警告。所以,这是行不通的。还有别的办法吗?特定于C++11或C++14或更高版本的答案就可以了。在C++17之

下面是一个示例程序:

class Unignorable {
    operator void();
};

Unignorable foo()
{
    return Unignorable();
}

int main()
{
    foo();
    return 0;
}
不幸的是,我的编译器(clang-703.0.31)说:


并且不会在调用
foo()
时引发任何错误或警告。所以,这是行不通的。还有别的办法吗?特定于C++11或C++14或更高版本的答案就可以了。

在C++17之前,我想到了这种方法:

#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();
}

然后强制将警告设置为错误:

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

从其他答案和评论中总结,基本上您有3种选择:

  • 让C++17能够使用
    [[nodiscard]]
  • 在g++(也叫clang++)中,使用编译器扩展,如
    \uuuwur
    (已定义 作为
    \uuuu属性\(((\uu警告\未使用的\结果\))
    )或更便携的(仅限C++11及以上版本)
    [[gnu::警告\未使用的\结果]]
    属性
  • 在单元测试期间使用运行时检查来发现问题

  • 如果这三种方法都不可行,那么还有一种方法,那就是“负编译”。定义您的
    不可识别的
    ,如下所示:

    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
    };
    
    现在使用
    -DNEGATIVE_compile
    或其他编译器(如MSVC)中的等效工具进行编译。无论结果在何处不被忽略,它都会给出错误:

    但是,如果忽略结果,则不会给出任何错误:

    使用任何现代的代码浏览器(如eclipse cdt),您都可以找到所有出现的
    foo()
    ,并修复那些没有给出错误的地方。在新编译中,只需删除“负编译”的预定义宏

    这可能比简单地查找
    foo()
    并检查其返回要好一些,因为可能有许多函数,例如
    foo()
    ,您可能不想忽略返回值


    这有点乏味,但对于所有版本的C++都适用,所有的编译器都有。

    < P>如果你使用MFC,你可以在函数声明之前尝试<强> CuffjReals>/Stuti>。
    有关它的更多信息,请参见

    是否确定存在到
    void
    的隐式转换?我在标准中找不到关于它的任何东西。(但我甚至不确定会转换什么。)好吧,当返回值没有“receiver”时,所有发生的事情都是构造和销毁一个临时对象。为此,C++17将有一个。wiki中的引用写入std::err,但您始终可以抛出一个异常。相关:。。。而且。。。这是一种很有趣的方法,我对它投了赞成票,但理想情况下,我正在寻找编译时解决方案。我不担心调用方破坏它的能力,因为他们总是可以通过将结果赋给某个对象,然后干脆不使用该值来破坏它。@GregHewgill那么我认为你在c++17之前运气不好,除非编译器在G++中扩展(可能也是clang++),我们还可以使用
    \uuuuwur
    作为
    \uuuuuuuu属性((\uuuuu警告\u未使用的\uuuuuuuuu结果))的速记宏。
    。此宏在
    ::system(…)
    函数之后使用。
    int foo() __attribute__ ((warn_unused_result));
    int foo(){return 123;}
    
    int main()
    {
        foo(); //compiler warning
        auto i = foo(); //valid
    }
    
    clang++ -std=c++1z -Werror="unused-result"
    
    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
    };
    
    auto x = foo();  // error
    
    foo(); // no error