2016-09-05 17 views
23

मैं यह निर्धारित करने की कोशिश कर रहा हूं कि सी ++ फ़ंक्शन को इस तरह से घोषित किया जा सकता है कि वापसी मूल्य को अनदेखा नहीं किया जा सकता है (आदर्श रूप से संकलन समय पर पता चला है)। मैंने private (या सी ++ 11, delete डी) operator void() के साथ एक वर्ग घोषित करने का प्रयास किया जब वापसी मूल्य अप्रयुक्त होने पर शून्य में अंतर्निहित रूपांतरण को पकड़ने का प्रयास किया गया।क्या सी ++ फ़ंक्शन घोषित किया जा सकता है कि वापसी मूल्य को अनदेखा नहीं किया जा सकता है?

class Unignorable { 
    operator void(); 
}; 

Unignorable foo() 
{ 
    return Unignorable(); 
} 

int main() 
{ 
    foo(); 
    return 0; 
} 

दुर्भाग्य से, मेरी संकलक (बजना-703.0.31) का कहना है::

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

और किसी भी त्रुटि को उठाने नहीं करता है या foo() को फोन पर चेतावनी

यहाँ एक उदाहरण कार्यक्रम है । तो, यह काम नहीं करेगा। ऐसा करने के लिए कोई और रास्ता नहीं है? सी ++ 11 या सी ++ 14 या बाद में विशिष्ट उत्तर ठीक होंगे। पहले C++ 17

+0

रनटाइम या संकलन समय? –

+6

http://stackoverflow.com/questions/12692892/force-returned-object-to-be-assign –

+1

क्या आप सकारात्मक हैं कि 'शून्य' में एक अंतर्निहित रूपांतरण है? मुझे इसके बारे में मानक में कुछ भी नहीं मिला। (लेकिन मुझे यह भी यकीन नहीं है कि क्या परिवर्तित किया जाएगा।) AFAIK, ऐसा तब होता है जब रिटर्न वैल्यू में "रिसीवर" नहीं होता है, एक अस्थायी वस्तु का निर्माण और विनाश होता है। इस उद्देश्य के लिए – molbdnilo

उत्तर

8

अन्य उत्तर से संक्षेप में & टिप्पणी, मूल रूप से आप 3 विकल्प हैं:

  1. होने के लिए सी ++ 17 जाओ [[nodiscard]]
  2. ग्राम में उपयोग करने में सक्षम ++ (भी बजना ++), __wur की तरह उपयोग संकलक एक्सटेंशन (परिभाषित +०१२३५१६४१०६__attribute__ ((__warn_unused_result__)) के रूप में), या अधिक पोर्टेबल (सी ++ 11 और ऊपर) [[gnu::warn_unused_result]] विशेषता।
  3. उपयोग क्रम चेकों इकाई परीक्षण

दौरान समस्या को पकड़ने के लिए तो इन 3 के सभी संभव नहीं हैं, तो एक और रास्ता है, जो "नकारात्मक संकलन" की तरह है। नीचे के रूप में अपने Unignorable परिभाषित करें:

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 जैसे अन्य compilers में बराबर के साथ संकलन।जहाँ भी परिणाम अनदेखा नहीं किया जाता यह कम से त्रुटियों दे देंगे:

auto x = foo(); // error 

हालांकि, यह किसी भी त्रुटि नहीं देंगे जहाँ भी परिणाम नजरअंदाज कर दिया है:

foo(); // no error 

किसी भी आधुनिक कोड ब्राउज़र का उपयोग करना (ग्रहण-सीडीटी की तरह), आपको foo() की सभी घटनाएं मिल सकती हैं और उन स्थानों को ठीक कर सकती हैं जो त्रुटि नहीं देते हैं। नए संकलन में, "NEGATIVE_COMPILE" के लिए पूर्व-परिभाषित मैक्रो को हटा दें।

यह foo() खोजने और इसकी वापसी की जांच के मुकाबले थोड़ा बेहतर हो सकता है, क्योंकि foo() जैसे कई फ़ंक्शन हो सकते हैं जहां आप वापसी मूल्य को अनदेखा नहीं करना चाहते हैं।

यह थोड़ा कठिन है, लेकिन सभी कंपाइलरों के साथ सी ++ के सभी संस्करणों के लिए काम करेगा।

5

इस दृष्टिकोण को ध्यान के लिए आया था:

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

सार: के बजाय वापसी एक टी, एक फ़ंक्शन एक angry<T> जो एक logic_error फेंक कर फोन करने वाले सज़ा देगा, तो मान नहीं है विनाश से पहले निकाला गया।

यह एक रन-टाइम समाधान है, जो एक सीमा है, लेकिन कम से कम इकाई परीक्षण के शुरू में पकड़ा जाना चाहिए।

एक चालाक उपयोगकर्ता के पाठ्यक्रम यह नष्ट कर सकते हैं:

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

यह एक दिलचस्प दृष्टिकोण है और मैंने इसे ऊपर उठाया है लेकिन आदर्श रूप में मैं संकलन समय समाधान की तलाश में हूं। मैं कॉलर्स को इसे हटाने के लिए क्षमता के बारे में चिंतित नहीं हूं, क्योंकि वे हमेशा परिणाम को कुछ सौंपकर और फिर उस मान का उपयोग नहीं कर सकते हैं। –

+0

@GregHewgill तो मुझे लगता है कि आप C++ 17 तक भाग्य से बाहर हो, संकलक एक्सटेंशन –

6

__attribute__ ((warn_unused_result)) देखें।

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" 
+0

जी में छोड़कर ++ (शायद ++ भी बजना), हम भी '' __wur' __attribute__ ((__warn_unused_result __)) के लिए एक आशुलिपि मैक्रो के रूप में उपयोग कर सकते हैं ' । इस मैक्रो का उपयोग ':: सिस्टम (...) 'फ़ंक्शन के बाद किया जाता है। – iammilind

संबंधित मुद्दे