Presentation is loading. Please wait.

Presentation is loading. Please wait.

Assignment #1 Advanced Programming in C /2017

Similar presentations


Presentation on theme: "Assignment #1 Advanced Programming in C /2017"— Presentation transcript:

1 Assignment #1 Advanced Programming in C++ 2016/2017
NPRG051 Advanced programming in C++ - Assignment #1

2 Assignment #1 – serialize deadline: Wed 15 Mar 14:00
NPRG051 Advanced programming in C++ - Assignment #1

3 Assignment #1 - serialize
class testB { public: std::string attrB1; enum E { E_X, E_Y, E_Z } attrB2; }; testB data = { “One”, E_X }; std::ofstream ofs( “data.json”); serialize::dump(ofs, data); testB data2; std::ifstream ifs( “data.json”); data2 = serialize::load(ifs); Implement two generic functions dump the contents of an object into a file load the contents of an object from a file Use json format: {"attrB1"="One","attrB2"=“E_X"} Problem: This “ideal” interface can not work in C++ the dump function cannot enumerate the data members of the object the load function cannot determine the type it should return NPRG051 Advanced programming in C++ - Assignment #1

4 Assignment #1 - serialize
In C++, we have (almost) no introspection Run-time introspection in C++: typeid(obj) returns a type descriptor (std::type_info) the type descriptor allows the following operations: compare two types for identity generate some implementation-defined unique name of the type it may be used as a key in associative containers typeid(obj) works as true run-time identification only if the dynamic (run-time) type of obj is inherited from a base class B the static (compile-time) type of obj is (a reference to) B B contains at least one virtual function in other cases, typeid(obj) just returns the static type of obj The type descriptor is not able to enumerate members of the type There is no such information at run-time (nor for virtual functions) NPRG051 Advanced programming in C++ - Assignment #1

5 Assignment #1 - serialize
Compile-time introspection in C++ It is possible to determine some properties of a type Example: the constant std::is_array_v< T> is true if T is an array the constant std::extent_v<T> returns the size of the array It is possible to determine whether a class contains a member of given name Example: the constant std::is_callable_v< F(A1,...,An)> is true if an object of type F may act as a function with arguments of types A1,...,An For class F, it effectively checks whether it contains a function named “operator()” which can be called with the specified argument types It requires extremely dirty tricks (combining SFINAE and decltype()) Essentially, the SFINAE trick allows checking whether a particular syntactically-correct expression is also type-correct, without causing error messages if it is not It can work only if the C++ source code contains the name of the member being checked The interface of a generic function to determine existence of T::name would be ugly: decltype( contains_member< T>([](auto && v){ v.name(); }))::value There is no way to enumerate the members of a class The compiler has the information but there is no interface in the language NPRG051 Advanced programming in C++ - Assignment #1

6 Assignment #1 - serialize
For problems like generic “serialize”, the user must cooperate The user must supply a “list” of members for each class involved In this assignment, we require non-intrusive form of support It is required to work over existing classes without their modification The “list” must be specified outside the class When calling the dump/load function, the user shall supply the “list” The “list” shall be handled at compile-time, therefore it must be a type The resulting syntax shall be: serialize::dump<list>(ofs, data); data2 = serialize::load<list>(ifs); For the load function, the “list” must also deliver the ability to create the object being returned NPRG051 Advanced programming in C++ - Assignment #1

7 Assignment #1 - serialize
testB data, data2; serialize::dump<listB>(ofs, data); data2 = serialize::load<listB>(ifs); listB shall be a class/struct which somehow describes the class testB It will not be instantiated – only the following members may be useful: nested classes or type definitions static constants static functions Such class/struct is usually called policy class we will use the name structpolicyB instead of listB in the examples we will use another kind of policy classes (e.g., enumpolicyE) to describe enumerations In our case, the policy class allows to: pass through all data members in an user-defined order create an object of type testB NPRG051 Advanced programming in C++ - Assignment #1

8 Assignment #1 - serialize
class testB { public: std::string attrB1; enum E { E_X, E_Y, E_Z } attrB2; }; In our cases, we want to: pass through all data members in an user-defined order create an object of type testB For creation, we need a function: struct structpolicyB { static auto create() { return testB{}; } // ... data2 = serialize::load<structpolicyB>(ifs); NPRG051 Advanced programming in C++ - Assignment #1

9 Assignment #1 - serialize
class testB { public: std::string attrB1; enum E { E_X, E_Y, E_Z } attrB2; }; For enumeration of attributes, we may theoretically use a type: struct structpolicyB { using attributes = std::tuple< something_about_attrB1, something_about_attrB2>; // ... In this code, std::tuple is merely a way to pack a list of types Describing attrB1 using only a type may be done using another policy class: struct something_about_attrB1 { static auto & f( testB & v) { return v.attrB1; } This is long and difficult to use – we prefer a different way... NPRG051 Advanced programming in C++ - Assignment #1

10 Assignment #1 - serialize
class testB { public: std::string attrB1; enum E { E_X, E_Y, E_Z } attrB2; }; The simpler way for enumeration of attributes is a function struct structpolicyB { static void make(/*...*/) { something_about_attrB1(/*...*/); something_about_attrB2(/*...*/); } What arguments we need? Something representing the json parser/generator A reference to an object of type testB NPRG051 Advanced programming in C++ - Assignment #1

11 Assignment #1 - serialize
class testB { public: std::string attrB1; enum E { E_X, E_Y, E_Z } attrB2; }; What arguments we need? Something representing the json parser/generator The users would not like writing two such functions We need a template to handle both cases at once A reference to an object of type testB struct structpolicyB { template< typename X> static void make(X && x, testB & v) { something_about_attrB1(x, v); something_about_attrB2(x, v); } NPRG051 Advanced programming in C++ - Assignment #1

12 Assignment #1 - serialize
class testB { public: std::string attrB1; enum E { E_X, E_Y, E_Z } attrB2; }; How do we access the attribute? Passing a reference to the library code: template< typename X> static void make(X && x, testB & v) { string_attribute(x, v.attrB1); enum_attribute(x, v.attrB2); } It works as long as the references are accessible... NPRG051 Advanced programming in C++ - Assignment #1

13 Assignment #1 - serialize
class testA { public: int get_A1() const { return attrA1; } void set_A1( int x) { attrA1 = x; } private: int attrA1; }; What if the attribute is accessible only through get/set? Passing a reference to the library code: template< typename X> static void make(X && x, testA & v) { int_attribute(x, v.get_A1(), v.set_A1(/*???*/)); } Completely wrong! What is the argument of set? It always calls set even if we want only to get NPRG051 Advanced programming in C++ - Assignment #1

14 Assignment #1 - serialize
class testA { public: int get_A1() const { return attrA1; } void set_A1( int x) { attrA1 = x; } private: int attrA1; }; What if the attribute is accessible only through get/set? template< typename X> static void make(X && x, testA & v) { int_attribute(x, [&v]() { return v.get_A1(); }, [&v](int x) { v.set_A1(x); }); } int_attribute receives two functors and calls one of them, depending on the type X The use of lambdas allows to invoke only one of the get/set functions but it does not solve all problems... NPRG051 Advanced programming in C++ - Assignment #1

15 Assignment #1 - serialize
template< typename X> static void make(X && x, testA & v) { int_attribute(x, [&v]() { return v.get_A1(); }, [&v](int x) { v.set_A1(x); }); } Problem: we need writable access to testA even if we only want to read Solution: static void make(X && x) { int_attribute(x, [](const testA & v) { return v.get_A1(); }, [](testA & v, int n) { v.set_A1(n); }); Note: x now shall represent both the json file and the object being loaded/dumped, i.e., x shall be a structure containing two pointers or references NPRG051 Advanced programming in C++ - Assignment #1

16 Assignment #1 - serialize
Shorter implementation using auto template< typename X> static void make(X && x) { int_attribute(x, [](auto && v) { return v.get_A1(); }, [](auto && v, auto && x) { v.set_A1(x); }); } Even shorter (and safer) using pointers: [](auto v) { return v->get_A1(); }, [](auto v, auto && x) { v->set_A1(x); }); NPRG051 Advanced programming in C++ - Assignment #1

17 Assignment #1 - serialize
template< typename X> static void make(X && x) { int_attribute(x, [](auto && v) { return v.get_A1(); }, [](auto && v, auto && x) { v.set_A1(x); }); } Implementing int_attribute We need to do different things (dump/load), depending on the type of x This is a compile-time switch - function overloading can do the trick The two functions still need to be templates to accomodate the functor arguments template< typename SetF, typename GetF> void int_attribute(const dump_pair & x, SetF && sf, GetF && gF); void int_attribute(const load_pair & x, SetF && sf, GetF && gF); But there is still a problem... NPRG051 Advanced programming in C++ - Assignment #1

18 Assignment #1 - serialize
template< typename X> static void make(X && x) { int_attribute(x, [](auto && v) { return v.get_A1(); }, [](auto && v, auto && x) { v.set_A1(x); }); } Implementing int_attribute The dump_pair/load_pair shall contain a pointer/reference to the dumper/loader stream a pointer/reference to the object being dumped/accessed The code shall work for any type of object – it requires another template argument template< typename TObj, typename SetF, typename GetF> void int_attribute(const dump_pair< TObj> & x, SetF && sf, GetF && gF); void int_attribute(const load_pair< TObj> & x, SetF && sf, GetF && gF); NPRG051 Advanced programming in C++ - Assignment #1

19 Assignment #1 - serialize
class testB { /*...*/ }; class testA { public: enum E { E_X, E_Y, E_Z } attrA2; std::list< testB> attrA3; }; Handling non-trivial data members The functions shall receive a policy class describing the type of the attribute struct structpolicyA { template< typename X> static void make(X && x) { enum_attribute< enumpolicyE>(x, [](auto && v) -> auto && { return v.attrA2; }); struct_sequence_attribute< structpolicyB>(x, } NPRG051 Advanced programming in C++ - Assignment #1

20 Assignment #1 - serialize
class testA { public: enum E { E_X, E_Y, E_Z } attrA2; }; Describing enumerations We need a list of binary-string pairs (template enumeration_list) struct enumpolicyE { static auto create() return testB::E{}; } static enumeration_list< testB::E> enumeration() return { { testB::E_X, "X" }, { testB::E_Y, "Y" }, { testB::E_Z, "Z" } }; NPRG051 Advanced programming in C++ - Assignment #1

21 Assignment #1 - serialize
The assignment #1 You will receive three files: du1example.hpp – a sample data structure – do not touch! du1examplepolicy.hpp – a version of the corresponding policy classes You may change the policy classes (not their names) if you want/need du1test.cpp – a test based on the sample structures and policy classes – do not touch! You have to return the following files (via SIS): du1serialize.hpp – your implementation of dump/load the dump/load functions must be callable as used in du1test.cpp du1serialize.cpp – your implementation (non-template non-inline functions) du1examplepolicy.hpp – the policy classes corresponding to the original du1example.hpp and your du1serialize.hpp NPRG051 Advanced programming in C++ - Assignment #1

22 Assignment #1 - serialize
You have to return the following files (via SIS): du1serialize.hpp – your implementation of dump/load the dump/load functions must be callable as used in du1test.cpp testA xA = /*...*/; std::ofstream ofs{ fname }; serialize::dump< structpolicyA>(ofs, (const testA &)xA); std::ifstream ifs{ fname }; auto xAcopy = serialize::load< structpolicyA>(ifs); du1serialize.cpp – your implementation (non-template non-inline functions) du1examplepolicy.hpp – the policy classes corresponding to the original du1example.hpp and your du1serialize.hpp NPRG051 Advanced programming in C++ - Assignment #1

23 Assignment #1 - serialize
Your system shall support data members of the following data types: int std::string enumeration types (with policy class) sequential containers of struct/class types For all types, the system shall support access by reference, i.e. directly accessible public data members private data members indirectly accessible via a member function returning reference In addition, for data members of type int, the system shall support access by a pair of get/set methods NPRG051 Advanced programming in C++ - Assignment #1


Download ppt "Assignment #1 Advanced Programming in C /2017"

Similar presentations


Ads by Google