Assignment #1 Advanced Programming in C++ 2017/2018 1
Assignment #1 split deadline: Thu 12 Apr 23:59 2
using namespace splitter; std::istringstream iss("alpha:=10/50.1"); std::string x; int y; double z; iss >> split(x, ':', '=', y, '/', z); std::cout << "x = " << x << ", y = " << y << ", z = " << z << std::endl; Implement the function split In the namespace splitter Any number of arguments: R-value of type char L-value of any type T The operator >> must be defined for an L-value of type std::istream and and an L-value of type T Two L-values must never be adjacent The example prints x = alpha, y = 10, z = 50.1 3
using namespace splitter; std::istringstream iss("alpha:=10/50.1"); std::string x; int y; double z; iss >> split(x, ':', '=', y, '/', z); std::cout << "x = " << x << ", y = " << y << ", z = " << z << std::endl; Functionality When the result of split is used as the right operand of >> on an std::istream & Each L-value argument A is used (left-to-right) as follows: The input stream is read until the delimiter character or the EOF is reached The characters read (except the delimiter) are fed into the >> operator with A as the right operand If the >> operator fails or if it does not read all the characters, the operation throws an exception The delimiter is the next argument it must be an R-value of type char if there is no next argument, \n is used The characters including the delimiter are always removed (read) from the input stream 4
using namespace splitter; std::istringstream iss("alpha:=10/50.1"); std::string x; int y; double z; iss >> split(x, ':', '=', y, '/', z); std::cout << "x = " << x << ", y = " << y << ", z = " << z << std::endl; Functionality Each L-value argument A is used (left-to-right) as follows: The input stream is read until the delimiter character or the EOF is reached The delimiter is the next argument it must be an R-value of type char if there is no next argument, \n is used The characters including the delimiter are always removed (read) from the input stream For each R-value argument of type char which is not right to an L-value A character is read from the input stream and compared to the argument If there is mismatch or EOF, the operation throws an exception 5
using namespace splitter; std::istringstream iss("alpha:=10/50.1"); std::string x; int y; double z; Compile-time diagnostics A compilation error (preferably a static_assert) shall be triggered if Two L-value arguments are adjacent, or An R-value argument is of type different than char iss >> split(x, ':', '=', y, '/', z); std::cout << "x = " << x << ", y = " << y << ", z = " << z << std::endl; 6
using namespace splitter; std::istringstream iss("alpha:=10/50.1"); std::string x; int y; double z; iss >> split(x, ':', '=', y, '/', z); std::cout << "x = " << x << ", y = " << y << ", z = " << z << std::endl; Run-time diagnostics An exception (preferably a std::logic_error) shall be thrown if An explicitly specified delimiter (i.e. an R-value argument right to an L- value) is not found in (the remainder of) the input stream The conversion (by >>) of the characters encountered before the explicit or implicit delimiter fails or does not eat up all the characters An additional R-value argument (not right to an L-value) is not present as the next character in the input stream 7
Assignment #1 split Technical details 8
Put everything into a file named test01split.hpp Don t forget the inline keyword for all global functions/operators Use namespace splitter for all public parts The type returned by split Use whatever name you want The function split The operator>> defined for the type returned by split The operator will be found using argument-dependent lookup It s a good idea to put everything else into an unpublished namespace, e.g. splitter_impl NPRG051 Pokročilé programování v C++ - 2015/2016 - DÚ 9
Use recodex to submit and test the functionality of your solutions Submit only test01split.hpp to recodex recodex uses g++ 7.3 The points will be awarded based on manual inspection of the source codes submitted to recodex NPRG051 Pokročilé programování v C++ - 2015/2016 - DÚ 10
Assignment #1 split Hints 11
Hints To distinguisth lvalues from rvalues, observe what forwarding reference does: template< typename T> void f( T && p) If the actual argument is an rvalue of type U then T = U If the actual argument is an lvalue of type U then T = U & For performance, avoid repeated passing of parameter lists Pack them into a tuple Compare what the following tuple declarations do: template< typename... T> void f( T &&... p) { using tuple1 = std::tuple< std::remove_reference_t< T>...>; using tuple2 = std::tuple< T...>; using tuple3 = std::tuple< T &&...>; And observe the effect of the following statements: auto data1 = std::make_tuple( std::forward<t>(p)...); data1 contains a copy of argument values, its type is tuple1 (except for array arguments) auto data2 = std::tie(p...); } data2 contains a reference to argument values, its type is std::tuple< T &...> NPRG051 Pokročilé programování v C++ - 2015/2016 - DÚ 12
Hints The packed tuple shall be passed by reference The type list used in the declaration of the tuple cannot be altered In recursive implementations, two options are available Indexing template< std::size_t I, typename... T2> void f( std::tuple< T2...> & p) { // solve the I-th element of the tuple, then call the rest f< I+1>( p); } Two type lists template< typename... T> struct S { template< typename... T2> static void f( std::tuple< T2...> & p); }; Use partial specialization of struct S to remove front elements of the type list T NPRG051 Pokročilé programování v C++ - 2015/2016 - DÚ 13