online compiler and debugger for c/c++

code. compile. run. debug. share.
Source Code   
Language
/* ================================================================= Step 7 (for Solution see Step 8) ================================================================= */ #include "do_averages.h" #include <sstream> // std::istringstream // std::ostringstream #ifndef TEST int main() { do_averages(); } #else #include "pxt.h" int main() { { //////////////////////////////////////////////////////////// std::istringstream input{ "1 5 7" "\n" "1.5 7" "\n" "15.7" "\n" }; std::ostringstream output{}; PX(do_averages(input, output), output.str()) >>= "4.33333" "\n" "4.25" "\n" "15.7" "\n"; } //////////////////////////////////////////////////////////// { //////////////////////////////////////////////////////////// std::istringstream input{"\n"}; std::ostringstream output{}; PX(do_averages(input, output), output.str()) == ""; } //////////////////////////////////////////////////////////// { //////////////////////////////////////////////////////////// std::istringstream input{ "1 5 7" "\n" "1 S 7" "\n" "15.7" "\n" }; std::ostringstream output{}; PX(do_averages(input, output), output.str()) >>= "4.33333" "\n" "1" "\n" "15.7" "\n"; } //////////////////////////////////////////////////////////// } #endif
# TODO STEP 7 - Let the function `do_single_average` return a `bool`-result to indicate whether all the input was numeric or not. - When `do_averages` calls `do_single_average` and receives the result `false` it should show a message that it ignores this line of input. - If there has been non-numeric input the content of `sum_count` should NOT be considered for the decision whether to end the loop in `do_averages. HINT: The decision whether there has been non-numeric input in a line can be made in `do_single_average` by looking at both, the count of successfully read data items and the state of the `std::istringstream iss`: ```cpp … if (((result.count > 0) && !iss.eof()) || (iss.fail() && !is.eof())) return false; else return true; … ``` Why is the test that complicated? - If already seen some values but not yet having arrived at "eof" (which actually is "end of line" in this case) then there has been something in the input that was not numeric: ```cpp … (result.count > 0) && !iss.eof() … ``` - Same if extracting some value failed but the end has not been reached: ```cpp … iss.fail() && !iss.eof() … ``` - Both need to be or-ed together to get a `true` result if there have been errors and hence `false` must be returned from `do_single_average`. ----------------------------------------------------------------- TODO (optional - meant for further self-study only): - Further explore how the "state bits" for `fail` and `eof` are set in an `std::istream` depending on the validity of the the input when numeric values are extracted. - How can the above logic to test for invalid input be simplified if the line turned into an `std::istringstream` would **still contain** the trailing `'\n'`, which has been stripped off when the line was read into an `std::string` using `std::getline`? - Based on the above, how might `do_averages` "help" the called function `do_single_average` to simplify the test?
#ifndef PXT_off #ifndef PXT_ostream #define PXT_ostream std::cout #endif #define PX(...)\ PXT_namespace::PXT_class{__func__, __FILE__, __LINE__, #__VA_ARGS__, (__VA_ARGS__)} #if defined(PXT_HAVE_BOOST_TYPEINDEX)\ || defined(__has_include) && __has_include(<boost/type_index.hpp>) #include <boost/type_index.hpp> #define PT(...)\ PXT_namespace::PXT_helper(__func__, __FILE__, __LINE__, #__VA_ARGS__,\ boost::typeindex::type_id_with_cvr<__VA_ARGS__>()) #endif #if !defined(PX)\ || !defined(PT) struct PXT_dummy{ template<typename T> void operator==(T const&) const {} template<typename T> void operator*=(T const&) const {} template<typename T> void operator>>=(T const&) const {} template<typename T> void operator%=(T const&) const {} }; #if !defined(PX) #define PX(...) PXT_dummy{} #endif #if !defined(PT) #define PT(...) PXT_dummy{} #endif #endif #include <sstream> #include <iostream> namespace PXT_namespace { class PXT_class { bool done_{}; char const* func_; char const* file_; int const line_{}; char const* texpr_; std::stringstream streamed_result{}; std::stringstream expected_result{}; std::ostream& source_location() const; void plain_output(); void two_line_compare(); void multi_line_compare(); void glob_pattern_compare(); struct Result { unsigned long long total; unsigned long long failed; ~Result(); }; static Result counter; public: static std::ostream& out_stream; static bool ignore_expecations; template<typename T> PXT_class(char const* func, char const* file, int line, char const* texpr, T const& expr) : func_{func}, file_{file}, line_{line}, texpr_{texpr} { streamed_result.copyfmt(out_stream); streamed_result << expr; } ~PXT_class() { if (not done_) plain_output(); } template<typename T> void operator==(T const& expr) { expected_result.copyfmt(streamed_result); expected_result << expr; two_line_compare(); } void operator>>=(std::string lines) { expected_result << lines; multi_line_compare(); } void operator*=(std::string smatch) { glob_pattern_compare(); } }; } // namespace #ifdef PXT_header_only #include "pxt.cpp" #endif #endif
#include <iosfwd> void do_averages(std::istream&, std::ostream&); void do_averages();
#include "do_averages.h" #include <iostream> // std::cin // std::cout // std::istream // std::ostream #include <sstream> // std::istringstream // std::ostringstream #include <string> // std::getline // std::string struct sum_count { float sum; int count; }; void do_single_average(std::string line, sum_count& result) { std::istringstream iss{line}; float value; while (iss >> value) { result.sum += value; ++result.count; } } void do_averages(std::istream& in, std::ostream& out) { std::string line; while (std::getline(in, line)) { sum_count sc{0.0f, 0}; do_single_average(line, sc); if (sc.count == 0) return; out << sc.sum/sc.count << std::endl; } } void do_averages() { do_averages(std::cin, std::cout); }
#ifndef PXT_header_only #include "pxt.h" #endif #include <iostream> namespace PXT_namespace { std::ostream& PXT_class::out_stream{PXT_ostream}; PXT_class::Result PXT_class::counter{0, 0}; PXT_class::Result::~Result() { if (failed > 0) { PXT_class::out_stream << "** " << failed << " of " << total << " tests failed **" << std::endl; } else if (total > 0) { PXT_class::out_stream << "** ALL " << total << " TESTS PASSED **" << std::endl; } } std::ostream& PXT_class::source_location() const { return out_stream << file_ << ' ' << '[' << func_ << ':' << line_ << ']' << ' ' << texpr_; } void PXT_class::plain_output() { source_location() << " == " << streamed_result.str() << std::endl; } void PXT_class::two_line_compare() { done_ = true; ++counter.total; if (streamed_result.str() != expected_result.str()) { ++counter.failed; source_location() << '\n' << " = received: " << streamed_result.str() << '\n' << " ! expected: " << expected_result.str() << std::endl; } } void PXT_class::multi_line_compare() { std::string streamed_line{}; std::string expected_line{}; std::ostringstream common{}; while (std::getline(streamed_result, streamed_line), (expected_result >> std::ws), std::getline(expected_result, expected_line), !streamed_result.eof() && !expected_result.eof() && (streamed_line == expected_line)) { common << " = " << expected_line << '\n'; } done_ = true; ++counter.total; if (streamed_result.eof() && expected_result.eof()) return; // no difference ++counter.failed; if (streamed_result.eof()) { // less streamed than expected source_location() << '\n' << common.str() << " + expected: " << expected_line << std::endl; return; } if (expected_result.eof()) { // less expected than streamed source_location() << '\n' << common.str() << " + received: " << streamed_line << std::endl; return; } source_location() << '\n' // difference in streamed to expected << common.str() << " ~ received: " << streamed_line << '\n' << " ~ expected: " << expected_line << std::endl; } } // namespace

Compiling Program...

Command line arguments:
Standard Input: Interactive Console Text

                

                

Program is not being debugged. Click "Debug" button to start program in debug mode.

#FunctionFile:Line
VariableValue
RegisterValue
ExpressionValue