online compiler and debugger for c/c++

code. compile. run. debug. share.
Source Code   
Language
/* ================================================================= Step 12 (no Solution for the optional TODO part is provided) ================================================================= */ #include "do_averages.h" #include <sstream> // std::istringstream #ifndef TEST int main() { do_averages(); } #else #include "pxt.h" void typical_good_input() { { //////////////////////////////////////////////////////////// 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"; } //////////////////////////////////////////////////////////// } void some_empty_inputs() { { //////////////////////////////////////////////////////////// std::istringstream input{"\n"}; std::ostringstream output{}; PX(do_averages(input, output), output.str()) == ""; } //////////////////////////////////////////////////////////// { //////////////////////////////////////////////////////////// std::istringstream input{" \n"}; std::ostringstream output{}; PX(do_averages(input, output), output.str()) == ""; } //////////////////////////////////////////////////////////// } void some_invalid_inputs() { { //////////////////////////////////////////////////////////// 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" "non-numeric input - line ignored" "\n" "15.7" "\n"; } //////////////////////////////////////////////////////////// { //////////////////////////////////////////////////////////// std::istringstream input{ "1 5 7" "\n" "xxx 7" "\n" "1 xyz 7" "\n" "1 xyz" "\n" }; std::ostringstream output{}; PX(do_averages(input, output), output.str()) >>= "4.33333" "\n" "non-numeric input - line ignored" "\n" "non-numeric input - line ignored" "\n" "non-numeric input - line ignored" "\n"; } //////////////////////////////////////////////////////////// } void fails_on_my_mac_only() { { //////////////////////////////////////////////////////////// std::istringstream input{ "1 xyz" "\n" "1 abc" "\n" }; std::ostringstream output{}; PX(do_averages(input, output), output.str()) >>= "non-numeric input - line ignored" "\n" "non-numeric input - line ignored" "\n"; } //////////////////////////////////////////////////////////// } int main() { typical_good_input(); some_empty_inputs(); some_invalid_inputs(); // fails_on_my_mac_only(); } #endif
# TODO STEP 12 [nothing more - this step is only provided as solution] ----------------------------------------------------------------- TODO (optional - meant for further self-study only): Here are some ideas for more programming exercises based what has been achieved so far. These steps are mostly independent of each other so you make "pick and chose" according to what matches your interest best. - Put every class and function developed as part of this code - either into an anonymous namespace (if it only needs to be visible in a single translation unit); - or into the namespace `my` (if it needs to be visible across translation units) - Turn the helper function `do_single_average` into a local named lambda defined inside `do_averages`. - Generalize the `Averager` class into a "value processor" so that instead of calculating averages other things may be done, like eg. to determine the minimum and maximum value in a line. - If you feel comfortable with writing template classes you may generalize the type of values to be processed right from the start, but it is easier to postpone the "templatization" until a simple (non-template) class is available and only prepare that step with a type alieas (eg. `value_type`). - Define an interface `IValueProcessor` with the virtual functions `operator+=` and `print`. (The latter is useful as a helper for the implementation of `operator<<`). The definition of the type alias can go here too. - Have the current `Averager` implement that interface and now, when everything is in place re-compile and run the tests. - Review the current design under the point of view what is still missing to fully generalize `do_averages` to process the values in a line eg. in regard to their minima and maxima. - The final goal is to add another argument to `do_averages` that determines the "ValueProcessor" to be used, which can be any class implementing the `IValueProcessor` interface. - If you try to do that you will notice that this interface needs to have another method, to query if there have been some values seen. - Also, if other ways of "value processing" are added, the the functions `do_averages` and `do_single_averages` become misnomers and should propably be renamed. - Add a third argument of type `IValueProcessor&` to the function once named `do_averages` and provide an `Averager` object in the `main` (interactive and/or for automated testing). - To demonstrate the independance from just doing the "average" and another implementation of `IValueProcessor` to determine minima and maxima of a line. - Maybe test "interactive" only but preferably provide automated tests for it … lots of tests. - Based on an `std::vector<Averager>` "pivot" the current output: - averages should be calculated in columns (instead per line) - and a final line with the average (or the minima and maxima) of each column added. **Note:** This file will probably be extended with new ideas now and then. You are welcome to return from time to time if you are looking for more "programming challenges" based on this example. SO STAY TUNED.
#include "do_averages.h" #include "Averager.h" #include <iostream> // std::cin // std::cout // std::istream // std::ostream #include <sstream> // std::istringstream // std::ostringstream #include <string> // std::getline // std::string void do_single_average(std::string line, Averager& result) { std::istringstream iss{line}; float value; while (iss >> value) result += value; bool const received_some_values_but_not_seen_eol{ (result.getCount() > 0) && !iss.eof() }; bool const fail_bit_is_set_but_eof_bit_is_not{ iss.fail() && !iss.eof() }; if (received_some_values_but_not_seen_eol || fail_bit_is_set_but_eof_bit_is_not) throw "non-numeric input"; } void do_averages(std::istream& in, std::ostream& out) { std::string line; while (std::getline(in, line)) { Averager sc{}; try { do_single_average(line, sc); } catch (char const* errmsg) { out << errmsg << " - line ignored" << std::endl; continue; } if (sc.getCount() == 0) return; out << sc << std::endl; } } void do_averages() { do_averages(std::cin, std::cout); }
#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();
#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
#include "Averager.h" #include <iostream> namespace my { std::ostream& operator<<(std::ostream& lhs, Averager const& rhs) { return lhs << rhs.sum_/rhs.count_; } void operator+=(Averager& lhs, float rhs) { lhs.sum_ += rhs; ++lhs.count_; } }
#ifndef MY_AVERAGER_H_ #define MY_AVERAGER_H_ #include <iosfwd> class Averager { float sum_{0.0f}; int count_{0}; friend std::ostream& operator<<(std::ostream&, Averager const& rhs); friend void operator+=(Averager& lhs, float rhs); public: auto getCount() const { return count_; } }; #endif // include guard

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