├── 16th Study ├── src │ ├── .gitignore │ ├── variant │ │ ├── main.cpp │ │ ├── VariantGetter.hpp │ │ ├── VariantStorage.hpp │ │ ├── Variant.hpp │ │ ├── functional.hpp │ │ └── variant.vcxproj │ ├── expression │ │ ├── main.cpp │ │ ├── operators.hpp │ │ ├── Array.hpp │ │ ├── SArray.hpp │ │ └── expression.vcxproj │ └── 16th Study.sln ├── images │ └── struct_vs_union.png ├── 26. Discriminated Unions.md └── 27. Expression Templates.md ├── Textbook.jpg ├── 1st Study ├── basics.pdf ├── basics.pptx ├── tuple.hpp ├── example.d.ts └── seminar.md ├── 17th Study ├── Concepts.cpp └── Study.md ├── 2nd Study ├── addvalue.hpp ├── varprint1.hpp ├── varprint2.hpp ├── addspace.hpp ├── message.cpp ├── stacknontype.cpp ├── stackauto.cpp ├── foldtraverse.cpp ├── varusing.cpp ├── stacknontype.hpp ├── stackauto.hpp └── PR.md ├── 12th Study ├── image-20180507114808984.png ├── image-20180507115019952.png ├── image-20180507120526700.png ├── image-20180509002926900.png └── image-20180516000151118.png ├── 8th Study ├── print_type.h ├── class_template_argument.cpp ├── forward_reference.cpp ├── reference_collapsing.cpp ├── CMakeLists.txt └── perfect_forward.cpp ├── 11th Study ├── common │ ├── void_type.hpp │ └── integral_constant.hpp ├── type-function │ ├── transformation-traits │ │ ├── type_size.hpp │ │ ├── remove_reference.hpp │ │ ├── element_type.hpp │ │ ├── decay.hpp │ │ ├── add_qualifier.hpp │ │ ├── remove_qualifier.hpp │ │ └── add_reference.hpp │ └── predicate-traits │ │ ├── is_same.hpp │ │ └── plus_result.hpp ├── lifting-template-function │ ├── accum0.hpp │ ├── accum2.hpp │ ├── accum3.hpp │ ├── accum1.hpp │ └── accum_policy.hpp ├── policy-traits │ └── read-only-param.hpp ├── type-classification │ ├── is_void.hpp │ ├── is_pointer.hpp │ ├── is_class.hpp │ ├── is_funda.hpp │ ├── is_pointer_to_member.hpp │ ├── is_enum.hpp │ ├── is_array.hpp │ ├── is_function.hpp │ └── is_reference.hpp ├── detecting-members │ ├── has_begin.hpp │ ├── has_member_first.hpp │ ├── has_memtype.hpp │ └── has_size.hpp ├── other-traits-technique │ └── if_then_else.hpp └── sfinae-based-traits │ ├── is_default_constructible2.hpp │ ├── is_default_constructible1.hpp │ ├── is_valid.hpp │ └── is_convertible.hpp ├── .gitignore ├── LICENSE ├── README.md ├── 7th Study ├── Chap14.md └── Chap13.md ├── 5th Study └── Study.md └── 3rd Study └── Study.md /16th Study/src/.gitignore: -------------------------------------------------------------------------------- 1 | .vs/ 2 | x64/ 3 | *.filters -------------------------------------------------------------------------------- /Textbook.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CppKorea/CppTemplateStudy/HEAD/Textbook.jpg -------------------------------------------------------------------------------- /1st Study/basics.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CppKorea/CppTemplateStudy/HEAD/1st Study/basics.pdf -------------------------------------------------------------------------------- /1st Study/basics.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CppKorea/CppTemplateStudy/HEAD/1st Study/basics.pptx -------------------------------------------------------------------------------- /17th Study/Concepts.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CppKorea/CppTemplateStudy/HEAD/17th Study/Concepts.cpp -------------------------------------------------------------------------------- /2nd Study/addvalue.hpp: -------------------------------------------------------------------------------- 1 | template 2 | T addValue (T x) 3 | { 4 | return x + Val; 5 | } 6 | 7 | -------------------------------------------------------------------------------- /12th Study/image-20180507114808984.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CppKorea/CppTemplateStudy/HEAD/12th Study/image-20180507114808984.png -------------------------------------------------------------------------------- /12th Study/image-20180507115019952.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CppKorea/CppTemplateStudy/HEAD/12th Study/image-20180507115019952.png -------------------------------------------------------------------------------- /12th Study/image-20180507120526700.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CppKorea/CppTemplateStudy/HEAD/12th Study/image-20180507120526700.png -------------------------------------------------------------------------------- /12th Study/image-20180509002926900.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CppKorea/CppTemplateStudy/HEAD/12th Study/image-20180509002926900.png -------------------------------------------------------------------------------- /12th Study/image-20180516000151118.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CppKorea/CppTemplateStudy/HEAD/12th Study/image-20180516000151118.png -------------------------------------------------------------------------------- /16th Study/images/struct_vs_union.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CppKorea/CppTemplateStudy/HEAD/16th Study/images/struct_vs_union.png -------------------------------------------------------------------------------- /8th Study/print_type.h: -------------------------------------------------------------------------------- 1 | #include 2 | using boost::typeindex::type_id_with_cvr; 3 | 4 | #define print_type(var) do { \ 5 | std::cout << type_id_with_cvr().pretty_name() << std::endl; \ 6 | } while(0) 7 | -------------------------------------------------------------------------------- /11th Study/common/void_type.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // void_type.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef void_t_h 10 | #define void_t_h 11 | 12 | template using void_t = void; 13 | 14 | #endif /* void_t_h */ 15 | -------------------------------------------------------------------------------- /2nd Study/varprint1.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void print () 4 | { 5 | } 6 | 7 | template 8 | void print (T firstArg, Types... args) 9 | { 10 | std::cout << firstArg << '\n'; // print first argument 11 | print(args...); // call print() for remaining arguments 12 | } 13 | 14 | -------------------------------------------------------------------------------- /8th Study/class_template_argument.cpp: -------------------------------------------------------------------------------- 1 | template 2 | class S { 3 | public: 4 | S(T b) : a(b) { 5 | } 6 | private: 7 | T a; 8 | }; 9 | 10 | int main() { 11 | // S x(1); // Error before c++17: 12 | // the class template parameter T was not deduced 13 | // from the constructor call argument 1 14 | S x(1); 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /16th Study/src/variant/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Variant.hpp" 3 | 4 | using namespace std; 5 | 6 | int main() 7 | { 8 | Variant var(3); 9 | 10 | cout << var.is() << endl; 11 | var.visit([](auto const &val) 12 | { 13 | cout << val << endl; 14 | }); 15 | 16 | system("pause"); 17 | return 0; 18 | } -------------------------------------------------------------------------------- /8th Study/forward_reference.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "print_type.h" 3 | 4 | template void f(T&& p) { 5 | T x = p; 6 | print_type(x); 7 | } 8 | 9 | template void g(T&& p) { 10 | std::remove_reference_t x = p; 11 | print_type(x); 12 | } 13 | 14 | int main() { 15 | int i = 0; 16 | f(i); 17 | g(i); 18 | 19 | return 0; 20 | } 21 | 22 | -------------------------------------------------------------------------------- /11th Study/type-function/transformation-traits/type_size.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // size_type.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef sizeof_h 10 | #define sizeof_h 11 | 12 | template 13 | struct type_size { 14 | static constexpr std::size_t value = sizeof(T); 15 | }; 16 | 17 | #endif /* sizeof_h */ 18 | -------------------------------------------------------------------------------- /2nd Study/varprint2.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | void print (T arg) 5 | { 6 | std::cout << arg << '\n'; // print passed argument 7 | } 8 | 9 | template 10 | void print (T firstArg, Types... args) 11 | { 12 | print(firstArg); // call print() for the first argument 13 | print(args...); // call print() for remaining arguments 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /16th Study/src/variant/VariantGetter.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | template 4 | struct VariantGetter 5 | { 6 | template 7 | static auto apply(const Data &obj) 8 | { 9 | return VariantGetter::apply(obj.tail_); 10 | }; 11 | }; 12 | 13 | template <> 14 | struct VariantGetter<0> 15 | { 16 | template 17 | static auto apply(const Data &obj) 18 | { 19 | return obj.head_; 20 | }; 21 | }; 22 | 23 | -------------------------------------------------------------------------------- /8th Study/reference_collapsing.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "print_type.h" 4 | int main() { 5 | using RCI = int const&; 6 | RCI volatile&& r = 42; // OK: r has type int const& 7 | using RRI = int&&; 8 | RRI const&& rr = 42; // OK: rr has type int&& 9 | 10 | print_type(r); 11 | print_type(rr); 12 | 13 | RCI const r1 = 42; 14 | print_type(r1); // int const& 15 | 16 | int i = 0; 17 | RRI const& r2 = i; 18 | print_type(r2); // int& 19 | 20 | return 0; 21 | }; 22 | -------------------------------------------------------------------------------- /11th Study/lifting-template-function/accum0.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // accum0.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef accum0_h 10 | #define accum0_h 11 | 12 | template 13 | T accum (T const* beg, T const* end) 14 | { 15 | T total {}; 16 | while (beg != end) { 17 | total = total + *beg; 18 | ++beg; 19 | } 20 | return total; 21 | } 22 | 23 | #endif /* accum0_h */ 24 | -------------------------------------------------------------------------------- /2nd Study/addspace.hpp: -------------------------------------------------------------------------------- 1 | template 2 | class AddSpace 3 | { 4 | private: 5 | T const& ref; // refer to argument passed in constructor 6 | public: 7 | AddSpace(T const& r): ref(r) { 8 | } 9 | friend std::ostream& operator<< (std::ostream& os, AddSpace s) { 10 | return os << s.ref << ' '; // output passed argument and a space 11 | } 12 | }; 13 | 14 | template 15 | void print (Args... args) { 16 | ( std::cout << ... << AddSpace(args) ) << '\n'; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /11th Study/policy-traits/read-only-param.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // read-only-param.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef read_only_param_h 10 | #define read_only_param_h 11 | 12 | #include "../other-traits/technique/if_then_else.hpp" 13 | 14 | template 15 | struct read_only_param { 16 | using type = typename if_then_else::type; 17 | }; 18 | 19 | #endif /* read_only_param_h */ 20 | -------------------------------------------------------------------------------- /11th Study/type-classification/is_void.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // is_void.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef is_void_h 10 | #define is_void_h 11 | 12 | #include "../common/integral_constant.hpp" 13 | 14 | template 15 | struct is_void : false_type {}; 16 | 17 | template <> 18 | struct is_void : true_type {}; 19 | 20 | template 21 | constexpr bool is_void_v = is_void::value; 22 | 23 | #endif /* is_void_h */ 24 | -------------------------------------------------------------------------------- /2nd Study/message.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template // take value of any possible nontype parameter (since C++17) 4 | class Message { 5 | public: 6 | void print() { 7 | std::cout << T << '\n'; 8 | } 9 | }; 10 | 11 | int main() 12 | { 13 | Message<42> msg1; 14 | msg1.print(); // initialize with int 42 and print that value 15 | 16 | static char const s[] = "hello"; 17 | Message msg2; // initilize with char const[6] "hello" 18 | msg2.print(); // and print that value 19 | } 20 | 21 | -------------------------------------------------------------------------------- /8th Study/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED (VERSION 3.0) 2 | 3 | FIND_PACKAGE(Boost) 4 | INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) 5 | MESSAGE("boost include ${Boost_INCLUDE_DIRS}") 6 | 7 | SET(CMAKE_CXX_STANDARD 14) 8 | 9 | SET(CMAKE_CXX_FLAGS "-g -Wall -Wextra ${CMAKE_CXX_FLAGS}") 10 | 11 | ADD_EXECUTABLE(reference_collapsing reference_collapsing.cpp) 12 | ADD_EXECUTABLE(forward_reference forward_reference.cpp) 13 | ADD_EXECUTABLE(perfect_forward perfect_forward.cpp) 14 | ADD_EXECUTABLE(class_template_argument class_template_argument.cpp) 15 | -------------------------------------------------------------------------------- /16th Study/src/variant/VariantStorage.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | template 4 | union VariantStorage; 5 | 6 | template 7 | union VariantStorage 8 | { 9 | public: 10 | Head head_; 11 | VariantStorage tail_; 12 | 13 | public: 14 | VariantStorage() {}; 15 | VariantStorage(const Head &head) 16 | : head_(head) {}; 17 | 18 | template 19 | VariantStorage(const T &val) 20 | : tail_(val) {}; 21 | }; 22 | 23 | template<> 24 | union VariantStorage<> 25 | { 26 | }; -------------------------------------------------------------------------------- /11th Study/detecting-members/has_begin.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // has_begin.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef has_begin_h 10 | #define has_begin_h 11 | 12 | #include "..common/integral_constant.hpp" 13 | #include "..common/void_type.hpp" 14 | 15 | template > 16 | struct has_begin : false_type {}; 17 | 18 | template 19 | struct has_begin().begin())>> : true_type {}; 20 | 21 | #endif /* has_begin_h */ 22 | -------------------------------------------------------------------------------- /11th Study/other-traits-technique/if_then_else.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // if_then_else.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef if_then_else_h 10 | #define if_then_else_h 11 | 12 | template 13 | struct if_then_else { 14 | using type = TrueType; 15 | }; 16 | 17 | template 18 | struct if_then_else { 19 | using type = FalseType; 20 | }; 21 | 22 | #endif /* if_then_else_h */ 23 | -------------------------------------------------------------------------------- /11th Study/detecting-members/has_member_first.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // has_member_first.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef has_member_first_h 10 | #define has_member_first_h 11 | 12 | #include "../common/integral_constant.hpp" 13 | #include "../common/void_type.hpp" 14 | 15 | template > 16 | struct has_member_first : false_type {}; 17 | 18 | template 19 | struct has_member_first> : true_type {}; 20 | 21 | #endif /* has_member_first_h */ 22 | -------------------------------------------------------------------------------- /11th Study/type-classification/is_pointer.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // is_pointer.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef is_pointer_h 10 | #define is_pointer_h 11 | 12 | #include "../common/integral_constant.hpp" 13 | 14 | template 15 | struct is_pointer : false_type {}; 16 | 17 | template 18 | struct is_pointer : true_type { 19 | using base_type = T; 20 | }; 21 | 22 | template 23 | constexpr bool is_pointer_v = is_pointer::value; 24 | 25 | #endif /* is_pointer_h */ 26 | -------------------------------------------------------------------------------- /11th Study/type-function/predicate-traits/is_same.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // is_same.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef is_same_h 10 | #define is_same_h 11 | 12 | #include "../../common/integral_constant.hpp" 13 | 14 | template 15 | struct is_same : false_type { 16 | }; 17 | 18 | template 19 | struct is_same : true_type { 20 | }; 21 | 22 | template 23 | constexpr bool is_same_v = is_same::value; 24 | 25 | #endif /* is_same_h */ 26 | -------------------------------------------------------------------------------- /11th Study/detecting-members/has_memtype.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // has_memtype.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef has_memtype_h 10 | #define has_memtype_h 11 | 12 | #include "../common/integral_constant.hpp" 13 | #include "../common/void_type.hpp" 14 | 15 | #define DEFINE_HAS_TYPE(MemType) \ 16 | template > \ 17 | struct has_##MemType : false_type {}; \ 18 | template \ 19 | struct has_##MemType> : true_type {}; 20 | 21 | #endif /* has_memtype_h */ 22 | -------------------------------------------------------------------------------- /11th Study/common/integral_constant.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // integral_constant.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef integral_constant_h 10 | #define integral_constant_h 11 | 12 | template 13 | struct integral_constant { 14 | using type = T; 15 | static constexpr T value = val; 16 | }; 17 | 18 | template 19 | using bool_constant = integral_constant; 20 | 21 | using true_type = bool_constant; 22 | using false_type = bool_constant; 23 | 24 | #endif /* integral_constant_h */ 25 | -------------------------------------------------------------------------------- /11th Study/type-classification/is_class.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // is_class.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef is_class_h 10 | #define is_class_h 11 | 12 | #include "../common/integral_constant.hpp" 13 | #include "../common/void_type.hpp" 14 | 15 | template > 16 | struct is_class : false_type {}; 17 | 18 | template 19 | struct is_class> : true_type {}; 20 | 21 | template 22 | constexpr bool is_class_v = is_class::value; 23 | 24 | #endif /* is_class_h */ 25 | -------------------------------------------------------------------------------- /2nd Study/stacknontype.cpp: -------------------------------------------------------------------------------- 1 | #include "stacknontype.hpp" 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | Stack int20Stack; // stack of up to 20 ints 8 | Stack int40Stack; // stack of up to 40 ints 9 | Stack stringStack; // stack of up to 40 strings 10 | 11 | // manipulate stack of up to 20 ints 12 | int20Stack.push(7); 13 | std::cout << int20Stack.top() << '\n'; 14 | int20Stack.pop(); 15 | 16 | // manipulate stack of up to 40 strings 17 | stringStack.push("hello"); 18 | std::cout << stringStack.top() << '\n'; 19 | stringStack.pop(); 20 | } 21 | 22 | -------------------------------------------------------------------------------- /11th Study/detecting-members/has_size.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // has_size.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef has_size_h 10 | #define has_size_h 11 | 12 | #include "../common/integral_constant.hpp" 13 | #include "../common/void_type.hpp" 14 | #include "../type-function/transformation-traits/remove_reference.hpp" 15 | 16 | template > 17 | struct has_size_type : false_type {}; 18 | 19 | template 20 | struct has_size_type::size_type>> : true_type {}; 21 | 22 | #endif /* has_size_h */ 23 | -------------------------------------------------------------------------------- /11th Study/type-classification/is_funda.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // is_funda.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef is_funda_h 10 | #define is_funda_h 11 | 12 | #include "../common/integral_constant.hpp" 13 | 14 | template 15 | struct is_funda : false_type {}; 16 | 17 | template <> 18 | struct is_funda : true_type {}; 19 | template <> 20 | struct is_funda : true_type {}; 21 | template <> 22 | struct is_funda : true_type {}; 23 | 24 | //... 25 | 26 | template 27 | constexpr bool is_funda_v = is_funda::value; 28 | 29 | #endif /* is_funda_h */ 30 | -------------------------------------------------------------------------------- /11th Study/lifting-template-function/accum2.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // accum2.h 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef accum2_h 10 | #define accum2_h 11 | 12 | #include "accum_policy.hpp" 13 | 14 | template class Policy = sum_policy> 15 | auto accum(T const* beg, T const* end) 16 | { 17 | using accum_type = typename Policy::accum_type; 18 | accum_type total = Policy::identity(); 19 | while (beg != end) { 20 | total = Policy::accum(total, *beg); 21 | ++beg; 22 | } 23 | return total; 24 | } 25 | 26 | #endif /* accum2_h */ 27 | -------------------------------------------------------------------------------- /11th Study/sfinae-based-traits/is_default_constructible2.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // is_default_constructible2.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef is_default_constructible2_h 10 | #define is_default_constructible2_h 11 | 12 | #include "../common/integral_constant.hpp" 13 | 14 | template using void_t = void; 15 | 16 | template > 17 | struct is_default_constructible : std::false_type {}; 18 | 19 | template 20 | struct is_default_constructible> : std::true_type {}; 21 | 22 | #endif /* is_default_constructible2_h */ 23 | -------------------------------------------------------------------------------- /2nd Study/stackauto.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "stackauto.hpp" 4 | 5 | int main() 6 | { 7 | Stack int20Stack; // stack of up to 20 ints 8 | Stack stringStack; // stack of up to 40 strings 9 | 10 | // manipulate stack of up to 20 ints 11 | int20Stack.push(7); 12 | std::cout << int20Stack.top() << '\n'; 13 | auto size1 = int20Stack.size(); 14 | 15 | // manipulate stack of up to 40 strings 16 | stringStack.push("hello"); 17 | std::cout << stringStack.top() << '\n'; 18 | auto size2 = stringStack.size(); 19 | 20 | if (!std::is_same_v) { 21 | std::cout << "size types differ" << '\n'; 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /11th Study/lifting-template-function/accum3.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // accum3.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef accum3_h 10 | #define accum3_h 11 | 12 | #include "accum_policy.hpp" 13 | 14 | template class Policy = sum_policy> 15 | auto accum(Iter beg, Iter end) 16 | { 17 | using value_type = typename std::iterator_traits::value_type; 18 | 19 | auto total = Policy::identity(); 20 | while (beg != end) { 21 | total = Policy::accum(total, *beg); 22 | ++beg; 23 | } 24 | return total; 25 | } 26 | 27 | #endif /* accum3_h */ 28 | -------------------------------------------------------------------------------- /11th Study/type-function/transformation-traits/remove_reference.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // remove_reference.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef remove_reference_h 10 | #define remove_reference_h 11 | 12 | template 13 | struct remove_reference { 14 | using type = T; 15 | }; 16 | 17 | template 18 | struct remove_reference { 19 | using type = T; 20 | }; 21 | 22 | template 23 | struct remove_reference { 24 | using type = T; 25 | }; 26 | 27 | template 28 | using remove_reference_t = typename remove_reference::type; 29 | 30 | #endif /* remove_reference_h */ 31 | -------------------------------------------------------------------------------- /11th Study/type-classification/is_pointer_to_member.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // is_pointer_to_member.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef is_pointer_to_member_h 10 | #define is_pointer_to_member_h 11 | 12 | #include "../common/integral_constant.hpp" 13 | 14 | template 15 | struct is_pointer_to_member : false_type { 16 | }; 17 | 18 | template 19 | struct is_pointer_to_member : true_type { 20 | using member_type = T; 21 | using class_type = C; 22 | }; 23 | 24 | template 25 | constexpr bool is_pointer_to_member_v = is_pointer_to_member::value; 26 | 27 | #endif /* is_pointer_to_member_h */ 28 | -------------------------------------------------------------------------------- /11th Study/type-function/transformation-traits/element_type.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // element_type.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef element_type_h 10 | #define element_type_h 11 | 12 | template 13 | struct element_type { 14 | using type = typename T::value_type; 15 | }; 16 | 17 | // for array of unknown bound 18 | template 19 | struct element_type { 20 | using type = T; 21 | }; 22 | 23 | // for array of known bound 24 | template 25 | struct element_type { 26 | using type = T; 27 | }; 28 | 29 | template 30 | using element_t = typename element_type::type; 31 | 32 | #endif /* element_type_h */ 33 | -------------------------------------------------------------------------------- /11th Study/type-classification/is_enum.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // is_enum.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef is_enum_h 10 | #define is_enum_h 11 | 12 | #include "is_funda.hpp" 13 | #include "is_pointer.hpp" 14 | #include "is_reference.hpp" 15 | #include "is_array.hpp" 16 | #include "is_pointer_to_member.hpp" 17 | #include "is_function.hpp" 18 | #include "is_class.hpp" 19 | 20 | template 21 | struct is_enum { 22 | static constexpr bool value = 23 | !is_funda_v && 24 | !is_pointer_v && 25 | !is_reference_v && 26 | !is_array_v && 27 | !is_pointer_to_member_v && 28 | !is_function_v && 29 | !is_class_v; 30 | }; 31 | 32 | #endif /* is_enum_h */ 33 | -------------------------------------------------------------------------------- /11th Study/type-classification/is_array.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // is_array.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef is_array_h 10 | #define is_array_h 11 | 12 | #include "../common/integral_constant.hpp" 13 | 14 | template 15 | struct is_array : false_type {}; 16 | 17 | template 18 | struct is_array : true_type { 19 | using base_type = T; 20 | static constexpr std::size_t size = N; 21 | }; 22 | template 23 | struct is_array : true_type { 24 | using base_type = T; 25 | static constexpr std::size_t size = 0; 26 | }; 27 | 28 | template 29 | constexpr bool is_array_v = is_array::value; 30 | 31 | #endif /* is_array_h */ 32 | -------------------------------------------------------------------------------- /2nd Study/foldtraverse.cpp: -------------------------------------------------------------------------------- 1 | // define binary tree structure and traverse helpers: 2 | struct Node { 3 | int value; 4 | Node* left; 5 | Node* right; 6 | Node (int i=0) : value(i), left(nullptr), right(nullptr) { 7 | } 8 | // ... 9 | }; 10 | auto left = &Node::left; 11 | auto right = &Node::right; 12 | 13 | // traverse tree, using fold expression: 14 | template 15 | Node* traverse (T np, TP... paths) { 16 | return (np ->* ... ->* paths); // np ->* paths1 ->* paths2 ... 17 | } 18 | 19 | int main() 20 | { 21 | // init binary tree structure: 22 | Node* root = new Node{0}; 23 | root->left = new Node{1}; 24 | root->left->right = new Node{2}; 25 | // ... 26 | 27 | // traverse binary tree: 28 | Node* node = traverse(root, left, right); 29 | // ... 30 | } 31 | 32 | -------------------------------------------------------------------------------- /11th Study/lifting-template-function/accum1.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // accum1.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef accum1_h 10 | #define accum1_h 11 | 12 | template 13 | struct accum_traits; 14 | 15 | template <> 16 | struct accum_traits { 17 | using type = int; 18 | static constexpr type identity() { 19 | return 0; 20 | } 21 | }; 22 | 23 | template 24 | auto accum(T const* beg, T const* end) 25 | { 26 | using accum_type = typename accum_traits::type; 27 | 28 | accum_type total = accum_traits::identity(); 29 | while (beg != end) { 30 | total = total + *beg; 31 | ++beg; 32 | } 33 | return total; 34 | } 35 | 36 | #endif /* accum1_h */ 37 | -------------------------------------------------------------------------------- /8th Study/perfect_forward.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class C { 4 | public: 5 | C() {} 6 | int i; 7 | }; 8 | 9 | void g(C&) { std::cout << "C&" << std::endl; } 10 | void g(C const&) { std::cout << "C const&" << std::endl; } 11 | void g(C&&) { std::cout << "C&&" << std::endl; } 12 | 13 | template 14 | void forwardToG(T&& x) { 15 | g(static_cast(x)); // forward x to g() 16 | //g(x); // forward x to g() 17 | //g(std::forward(x)); // forward x to g() 18 | } 19 | 20 | int main() { 21 | C v; 22 | C const c; 23 | forwardToG(v); // eventually calls g(C&) 24 | forwardToG(c); // eventually calls g(C const&) 25 | forwardToG(C()); // eventually calls g(C&&) 26 | forwardToG(std::move(v)); // eventually calls g(C&&) 27 | 28 | g(v); 29 | g(c); 30 | g(C()); 31 | g(std::move(v)); 32 | 33 | return 0; 34 | } 35 | 36 | -------------------------------------------------------------------------------- /11th Study/sfinae-based-traits/is_default_constructible1.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // is_default_constructible1.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef is_default_constructible1_h 10 | #define is_default_constructible1_h 11 | 12 | #include "../common/integral_constant.hpp" 13 | 14 | template 15 | struct is_default_constructible_helper { 16 | private: 17 | template 18 | static true_type test(void*); 19 | 20 | template 21 | static false_type test(...); 22 | 23 | public: 24 | using type = decltype(test(nullptr)); 25 | }; 26 | 27 | template 28 | struct is_default_constructible : is_default_constructible_helper::type {}; 29 | 30 | #endif /* is_default_constructible1_h */ 31 | -------------------------------------------------------------------------------- /16th Study/src/expression/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "SArray.hpp" 4 | #include "Array.hpp" 5 | 6 | using namespace std; 7 | 8 | void s_array() 9 | { 10 | Array x(5); 11 | Array y(5); 12 | 13 | for (size_t i = 0; i < 5; ++i) 14 | { 15 | x[i] = (int)i; 16 | y[i] = (int)-i; 17 | } 18 | 19 | auto op = A_Mult, SArray> 20 | ( 21 | A_Scalar(4), 22 | x.data() 23 | ); 24 | auto arr = Array, SArray>>(op); 25 | 26 | // auto ret = 2*x + x*y; //--> ?? 27 | auto ret = x + x*y; 28 | for (size_t i = 0; i < ret.size(); ++i) 29 | // cout << ret[i] << endl; //--> ??? 30 | cout << ret.data()[i] << endl; 31 | } 32 | 33 | int main() 34 | { 35 | s_array(); 36 | 37 | system("pause"); 38 | return 0; 39 | } -------------------------------------------------------------------------------- /11th Study/type-function/predicate-traits/plus_result.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // plus_result.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef plus_result_h 10 | #define plus_result_h 11 | 12 | #include "../../common/integral_constant.hpp" 13 | #include "../../common/void_type.hpp" 14 | 15 | template > 16 | struct has_plus : false_type {}; 17 | 18 | template 19 | struct has_plus() + std::declval())>> : true_type {}; 20 | 21 | template 22 | static constexpr bool has_plus_v = has_plus::value; 23 | 24 | template > 25 | struct plus_result { 26 | using type = decltype(std::declval() + std::declval()); 27 | }; 28 | 29 | template 30 | struct plus_result { 31 | }; 32 | 33 | #endif /* plus_result_h */ 34 | -------------------------------------------------------------------------------- /11th Study/type-function/transformation-traits/decay.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // decay.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef decay_h 10 | #define decay_h 11 | 12 | #include "remove_qualifier.hpp" 13 | 14 | template 15 | struct decay : remove_cv { 16 | }; 17 | 18 | // for array of unknown bound 19 | template 20 | struct decay { 21 | using type = T*; 22 | }; 23 | 24 | // for array of known bound 25 | template 26 | struct decay { 27 | using type = T*; 28 | }; 29 | 30 | template 31 | struct decay { 32 | using type = R(*)(Args...); 33 | }; 34 | 35 | // c-style variadic resolution 36 | template 37 | struct decay { 38 | using type = R(*)(Args..., ...); 39 | }; 40 | 41 | template 42 | using decay_t = typename decay::type; 43 | 44 | #endif /* decay_h */ 45 | -------------------------------------------------------------------------------- /11th Study/sfinae-based-traits/is_valid.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // is_valid.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef sfinae_helper_h 10 | #define sfinae_helper_h 11 | 12 | #include "../common/integral_constant.hpp" 13 | 14 | template ()(std::declval()...))> 16 | true_type is_valid_impl(void*); 17 | 18 | template 19 | false_type is_valid_impl(...); 20 | 21 | inline constexpr 22 | auto is_valid = [](auto f) { 23 | return [](auto&&... args) { 24 | return decltype(is_valid_impl(nullptr)){}; 25 | }; 26 | }; 27 | 28 | template 29 | struct type_wrapper { 30 | using type = T; 31 | }; 32 | 33 | template 34 | constexpr auto type_instance = type_wrapper{}; 35 | 36 | template 37 | T unwrap_type(type_wrapper); 38 | 39 | #endif /* is_valid_h */ 40 | -------------------------------------------------------------------------------- /11th Study/type-classification/is_function.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // is_function.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef is_function_h 10 | #define is_function_h 11 | 12 | #include 13 | #include "../common/integral_constant.hpp" 14 | 15 | template 16 | struct is_function : false_type {}; 17 | 18 | template 19 | struct is_function : true_type { 20 | using type = R; 21 | using param_type = std::tuple; 22 | static constexpr bool variadic = false; 23 | }; 24 | 25 | // c-style variadic parameter 26 | template 27 | struct is_function : true_type { 28 | using type = R; 29 | using params_type = std::tuple; 30 | static constexpr bool variadic = true; 31 | }; 32 | 33 | template 34 | constexpr bool is_function_v = is_function::value; 35 | 36 | #endif /* is_function_h */ 37 | -------------------------------------------------------------------------------- /11th Study/type-function/transformation-traits/add_qualifier.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // add_qualifier.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef add_qualifier_h 10 | #define add_qualifier_h 11 | 12 | template 13 | struct add_const { 14 | using type = T const; 15 | }; 16 | 17 | template 18 | struct add_const { 19 | using type = T const; 20 | }; 21 | 22 | template 23 | using add_const_t = typename add_const::type; 24 | 25 | template 26 | struct add_volatile { 27 | using type = T volatile; 28 | }; 29 | 30 | template 31 | struct add_volatile { 32 | using type = T volatile; 33 | }; 34 | 35 | template 36 | using add_volatile_t = typename add_const::type; 37 | 38 | template 39 | struct add_cv : add_const< add_volatile_t> { 40 | }; 41 | 42 | template 43 | using add_cv_t = typename add_cv::type; 44 | 45 | #endif /* add_qualifier_h */ 46 | -------------------------------------------------------------------------------- /11th Study/type-function/transformation-traits/remove_qualifier.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // remove_qualifier.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef remove_qualifier_h 10 | #define remove_qualifier_h 11 | 12 | template 13 | struct remove_const { 14 | using type = T; 15 | }; 16 | 17 | template 18 | struct remove_const { 19 | using type = T; 20 | }; 21 | 22 | template 23 | using remove_const_t = typename remove_const::type; 24 | 25 | template 26 | struct remove_volatile { 27 | using type = T; 28 | }; 29 | 30 | template 31 | struct remove_volatile { 32 | using type = T; 33 | }; 34 | 35 | template 36 | using remove_volatile_t = typename remove_const::type; 37 | 38 | template 39 | struct remove_cv : remove_const< remove_volatile_t> { 40 | }; 41 | 42 | template 43 | using remove_cv_t = typename remove_cv::type; 44 | 45 | #endif /* remove_qualifier_h */ 46 | -------------------------------------------------------------------------------- /2nd Study/varusing.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Customer 5 | { 6 | private: 7 | std::string name; 8 | public: 9 | Customer(std::string const& n) : name(n) { } 10 | std::string getName() const { return name; } 11 | }; 12 | 13 | struct CustomerEq { 14 | bool operator() (Customer const& c1, Customer const& c2) const { 15 | return c1.getName() == c2.getName(); 16 | } 17 | }; 18 | 19 | struct CustomerHash { 20 | std::size_t operator() (Customer const& c) const { 21 | return std::hash()(c.getName()); 22 | } 23 | }; 24 | 25 | // define class that combiles operator() for variadic base classes: 26 | template 27 | struct Overloader : Bases... 28 | { 29 | using Bases::operator()...; // OK since C++17 30 | }; 31 | 32 | int main() 33 | { 34 | // combine hasher and equality for customers in one type: 35 | using CustomerOP = Overloader; 36 | 37 | std::unordered_set coll1; 38 | std::unordered_set coll2; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /11th Study/lifting-template-function/accum_policy.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // accum_policy.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef accum_policy_h 10 | #define accum_policy_h 11 | 12 | template 13 | struct sum_policy; 14 | 15 | template <> 16 | struct sum_policy { 17 | public: 18 | using value_type = char; 19 | using accum_type = int; 20 | static constexpr accum_type identity() { 21 | return 0; 22 | } 23 | static constexpr accum_type accum(accum_type total, value_type value) { 24 | return total + value; 25 | } 26 | }; 27 | 28 | 29 | template 30 | struct mult_policy; 31 | 32 | template <> 33 | struct mult_policy { 34 | public: 35 | using value_type = char; 36 | using accum_type = int; 37 | static constexpr accum_type identity() { 38 | return 1; 39 | } 40 | static constexpr accum_type accum(accum_type total, value_type value) { 41 | return total * value; 42 | } 43 | }; 44 | 45 | #endif /* accum_policy_h */ 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 C++ Korea 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /11th Study/type-function/transformation-traits/add_reference.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // add_reference.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef add_reference_h 10 | #define add_reference_h 11 | 12 | template 13 | struct add_lvalue_reference { 14 | using type = T&; 15 | }; 16 | 17 | template <> 18 | struct add_lvalue_reference { 19 | using type = void; 20 | }; 21 | 22 | template <> 23 | struct add_lvalue_reference { 24 | using type = void const; 25 | }; 26 | 27 | template <> 28 | struct add_lvalue_reference { 29 | using type = void const volatile; 30 | }; 31 | 32 | template 33 | using add_lvalue_reference_t = typename add_lvalue_reference::type; 34 | 35 | 36 | template 37 | struct add_rvalue_reference { 38 | using type = T&&; 39 | }; 40 | 41 | template <> 42 | struct add_rvalue_reference { 43 | using type = void; 44 | }; 45 | 46 | template <> 47 | struct add_rvalue_reference { 48 | using type = void const; 49 | }; 50 | 51 | template <> 52 | struct add_rvalue_reference { 53 | using type = void const volatile; 54 | }; 55 | 56 | template 57 | using add_rvalue_reference_t = typename add_rvalue_reference::type; 58 | 59 | #endif /* add_reference_h */ 60 | -------------------------------------------------------------------------------- /11th Study/type-classification/is_reference.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // is_reference.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef is_reference_h 10 | #define is_reference_h 11 | 12 | #include "../common/integral_constant.hpp" 13 | #include "../other-traits-technique/if_then_else.hpp" 14 | 15 | template 16 | struct is_lvalue_reference : false_type {}; 17 | 18 | template 19 | struct is_lvalue_reference : true_type { 20 | using base_type = T; 21 | }; 22 | 23 | template 24 | using is_lvalue_reference_t = typename is_lvalue_reference::type; 25 | 26 | template 27 | constexpr bool is_lvalue_reference_v = is_lvalue_reference::value; 28 | 29 | template 30 | struct is_rvalue_reference : false_type {}; 31 | 32 | template 33 | struct is_rvalue_reference : true_type { 34 | using base_type = T; 35 | }; 36 | 37 | template 38 | using is_rvalue_reference_t = typename is_rvalue_reference::type; 39 | template 40 | constexpr bool is_rvalue_reference_v = is_rvalue_reference::value; 41 | 42 | template 43 | struct is_reference : if_then_else, is_lvalue_reference_t, is_rvalue_reference_t> {}; 44 | 45 | template 46 | constexpr bool is_reference_v = is_reference::value; 47 | 48 | #endif /* is_reference_h */ 49 | -------------------------------------------------------------------------------- /11th Study/sfinae-based-traits/is_convertible.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // is_convertible.hpp 3 | // cpptemples-ch19 4 | // 5 | // Created by yws6909 on 02/05/2018. 6 | // Copyright © 2018 yws6909. All rights reserved. 7 | // 8 | 9 | #ifndef is_convertible_h 10 | #define is_convertible_h 11 | 12 | #include "../common/integral_constant.hpp" 13 | #include "../type-classification/is_void.hpp" 14 | #include "../type-classification/is_array.hpp" 15 | #include "../type-classification/is_function.hpp" 16 | 17 | template || is_array_v || is_function_v> 18 | struct is_convertible_helper { 19 | private: 20 | static void aux(TO); 21 | 22 | template ()))> 23 | static true_type test(void*); 24 | 25 | template 26 | static false_type test(...); 27 | 28 | public: 29 | using type = decltype(test(nullptr)); 30 | }; 31 | 32 | template 33 | struct is_convertible_helper { 34 | using type = false_type; 35 | }; 36 | 37 | template 38 | struct is_convertible : is_convertible_helper::type {}; 39 | 40 | template 41 | using is_convertible_t = typename is_convertible::type; 42 | 43 | template 44 | constexpr bool is_convertible_v = is_convertible::value; 45 | 46 | #endif /* is_convertible_h */ 47 | -------------------------------------------------------------------------------- /2nd Study/stacknontype.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | class Stack { 6 | private: 7 | std::array elems; // elements 8 | std::size_t numElems; // current number of elements 9 | 10 | public: 11 | Stack(); // constructor 12 | void push(T const& elem); // push element 13 | void pop(); // pop element 14 | T const& top() const; // return top element 15 | bool empty() const { // return whether the stack is empty 16 | return numElems == 0; 17 | } 18 | std::size_t size() const { // return current number of elements 19 | return numElems; 20 | } 21 | }; 22 | 23 | template 24 | Stack::Stack () 25 | : numElems(0) // start with no elements 26 | { 27 | // nothing else to do 28 | } 29 | 30 | template 31 | void Stack::push (T const& elem) 32 | { 33 | assert(numElems < Maxsize); 34 | elems[numElems] = elem; // append element 35 | ++numElems; // increment number of elements 36 | } 37 | 38 | template 39 | void Stack::pop () 40 | { 41 | assert(!elems.empty()); 42 | --numElems; // decrement number of elements 43 | } 44 | 45 | template 46 | T const& Stack::top () const 47 | { 48 | assert(!elems.empty()); 49 | return elems[numElems-1]; 50 | } 51 | 52 | -------------------------------------------------------------------------------- /2nd Study/stackauto.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | class Stack { 6 | public: 7 | using size_type = decltype(Maxsize); 8 | private: 9 | std::array elems; // elements 10 | size_type numElems; // current number of elements 11 | public: 12 | Stack(); // constructor 13 | void push(T const& elem); // push element 14 | void pop(); // pop element 15 | T const& top() const; // return top element 16 | bool empty() const { // return whether the stack is empty 17 | return numElems == 0; 18 | } 19 | size_type size() const { // return current number of elements 20 | return numElems; 21 | } 22 | }; 23 | 24 | // constructor 25 | template 26 | Stack::Stack () 27 | : numElems(0) // start with no elements 28 | { 29 | // nothing else to do 30 | } 31 | 32 | template 33 | void Stack::push (T const& elem) 34 | { 35 | assert(numElems < Maxsize); 36 | elems[numElems] = elem; // append element 37 | ++numElems; // increment number of elements 38 | } 39 | 40 | template 41 | void Stack::pop () 42 | { 43 | assert(!elems.empty()); 44 | --numElems; // decrement number of elements 45 | } 46 | 47 | template 48 | T const& Stack::top () const 49 | { 50 | assert(!elems.empty()); 51 | return elems[numElems-1]; // return last element 52 | } 53 | 54 | -------------------------------------------------------------------------------- /1st Study/tuple.hpp: -------------------------------------------------------------------------------- 1 | namespace mystl 2 | { 3 | template 4 | class tuple; 5 | 6 | template 7 | class tuple 8 | { 9 | private: 10 | Head head_; 11 | 12 | public: 13 | tuple() {}; 14 | tuple(const Head &head) 15 | : head_(head) {}; 16 | 17 | auto _Get_head() const -> const Head& 18 | { 19 | return head_; 20 | }; 21 | }; 22 | 23 | template 24 | class tuple : public tuple 25 | { 26 | private: 27 | tuple tail_; 28 | 29 | public: 30 | tuple() : tuple() {}; 31 | tuple(const Head &head, const tuple &tail) 32 | : tuple(head), tail_(tail) {}; 33 | 34 | auto _Get_tail() const -> const tuple& 35 | { 36 | return tail_; 37 | }; 38 | }; 39 | 40 | template 41 | struct TupleGetter 42 | { 43 | template 44 | static auto apply(const Tuple &t) 45 | { 46 | return TupleGetter::apply(t._Get_tail()); 47 | }; 48 | }; 49 | 50 | template <> 51 | struct TupleGetter<0> 52 | { 53 | template 54 | static auto apply(const Tuple &t) 55 | { 56 | return t._Get_head(); 57 | }; 58 | }; 59 | 60 | template 61 | auto get(const Tuple &t) 62 | { 63 | return TupleGetter::apply(t); 64 | }; 65 | }; -------------------------------------------------------------------------------- /16th Study/src/variant/Variant.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "VariantStorage.hpp" 4 | #include "VariantGetter.hpp" 5 | 6 | #include "functional.hpp" 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | template 13 | class Variant 14 | { 15 | private: 16 | VariantStorage data_; 17 | size_t index_; 18 | 19 | public: 20 | //---- 21 | // CONSTRUCTORS 22 | //---- 23 | Variant() 24 | : index_(0) {}; 25 | 26 | template 27 | Variant(const T &val) 28 | : data_(val), 29 | index_(FindIndexOfT, T>::value) 30 | { 31 | }; 32 | 33 | //---- 34 | // ACCESSORS 35 | //---- 36 | template 37 | bool is() const 38 | { 39 | constexpr size_t N = FindIndexOfT, T>::value; 40 | return N == index_; 41 | }; 42 | 43 | template 44 | auto get() 45 | { 46 | constexpr size_t N = FindIndexOfT, T>::value; 47 | return get(); 48 | }; 49 | 50 | template 51 | auto get() 52 | { 53 | return VariantGetter::apply(data_); 54 | }; 55 | 56 | template 57 | void visit(Func &&func) const 58 | { 59 | if (index_ == -1) 60 | throw std::invalid_argument("value is not assigned."); 61 | 62 | _Visit(&func); 63 | }; 64 | 65 | private: 66 | template 67 | void _Visit(Func *func) const 68 | { 69 | if (is()) 70 | (*func)(get()); 71 | else if constexpr (sizeof...(Tail) > 0) 72 | _Visit(func); 73 | }; 74 | }; -------------------------------------------------------------------------------- /16th Study/src/expression/operators.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | /* ---------------------------------------------------------- 6 | TRAITS 7 | ---------------------------------------------------------- */ 8 | template 9 | class A_Traits 10 | { 11 | public: 12 | using Reference = const T&; 13 | }; 14 | 15 | template 16 | class A_Scalar 17 | { 18 | private: 19 | const T &s; 20 | 21 | public: 22 | constexpr A_Scalar(const T &v) 23 | : s(v) 24 | { 25 | }; 26 | 27 | constexpr const T& operator[](size_t) const 28 | { 29 | return s; 30 | }; 31 | 32 | constexpr size_t size() const 33 | { 34 | return 0; 35 | } 36 | }; 37 | 38 | /* ---------------------------------------------------------- 39 | OPERATORS 40 | ---------------------------------------------------------- */ 41 | template 42 | class A_Operator 43 | { 44 | public: 45 | typename A_Traits::Reference x_; 46 | typename A_Traits::Reference y_; 47 | 48 | public: 49 | A_Operator(const X &x, const Y &y) 50 | : x_(x), y_(y) 51 | { 52 | }; 53 | 54 | auto operator[](size_t index) const 55 | { 56 | return Operator()(x_[index], y_[index]); 57 | }; 58 | 59 | size_t size() const 60 | { 61 | assert(x_.size() == 0 || y_.size() == 0 || x_.size() == y_.size()); 62 | return x_.size() != 0 63 | ? x_.size() 64 | : y_.size(); 65 | }; 66 | }; 67 | 68 | template 69 | using A_Add = A_Operator>; 70 | 71 | template 72 | using A_Mult = A_Operator>; -------------------------------------------------------------------------------- /1st Study/example.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace std 2 | { 3 | export class ReverseIterator {} 4 | 5 | export class Entry {} 6 | } 7 | 8 | declare namespace std 9 | { 10 | export interface IArrayContainer {} 11 | 12 | export abstract class ArrayContainer> 13 | implements IArrayContainer 14 | { 15 | public begin(): ArrayIterator; 16 | public end(): ArrayIterator; 17 | 18 | public rbegin(): ArrayReverseIterator; 19 | public rend(): ArrayReverseIterator; 20 | } 21 | 22 | export class ArrayIterator> 23 | { 24 | public source(): Source; 25 | } 26 | export class ArrayReverseIterator> 27 | extends ReverseIterator 28 | < 29 | T, Source, 30 | ArrayIterator, 31 | ArrayReverseIterator 32 | > {} 33 | } 34 | 35 | declare namespace std 36 | { 37 | export interface IMapContainer {} 38 | 39 | export abstract class MapContainer> 40 | { 41 | public begin(): MapIterator; 42 | public end(): MapIterator; 43 | 44 | public rbegin(): MapReverseIterator; 45 | public rend(): MapReverseIterator; 46 | } 47 | 48 | export class MapIterator> 49 | implements IMapContainer 50 | { 51 | public source(): MapContainer; 52 | } 53 | export class MapReverseIterator> 54 | extends ReverseIterator 55 | < 56 | Entry, 57 | MapContainer, 58 | MapIterator, 59 | MapReverseIterator 60 | > {} 61 | } -------------------------------------------------------------------------------- /16th Study/src/16th Study.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26430.15 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "variant", "variant\variant.vcxproj", "{96150404-C730-4A8E-B912-BA33083AA7C5}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "expression", "expression\expression.vcxproj", "{A0529565-FE5E-4E98-A9E0-1093DAB3B73A}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {96150404-C730-4A8E-B912-BA33083AA7C5}.Debug|x64.ActiveCfg = Debug|x64 19 | {96150404-C730-4A8E-B912-BA33083AA7C5}.Debug|x64.Build.0 = Debug|x64 20 | {96150404-C730-4A8E-B912-BA33083AA7C5}.Debug|x86.ActiveCfg = Debug|Win32 21 | {96150404-C730-4A8E-B912-BA33083AA7C5}.Debug|x86.Build.0 = Debug|Win32 22 | {96150404-C730-4A8E-B912-BA33083AA7C5}.Release|x64.ActiveCfg = Release|x64 23 | {96150404-C730-4A8E-B912-BA33083AA7C5}.Release|x64.Build.0 = Release|x64 24 | {96150404-C730-4A8E-B912-BA33083AA7C5}.Release|x86.ActiveCfg = Release|Win32 25 | {96150404-C730-4A8E-B912-BA33083AA7C5}.Release|x86.Build.0 = Release|Win32 26 | {A0529565-FE5E-4E98-A9E0-1093DAB3B73A}.Debug|x64.ActiveCfg = Debug|x64 27 | {A0529565-FE5E-4E98-A9E0-1093DAB3B73A}.Debug|x64.Build.0 = Debug|x64 28 | {A0529565-FE5E-4E98-A9E0-1093DAB3B73A}.Debug|x86.ActiveCfg = Debug|Win32 29 | {A0529565-FE5E-4E98-A9E0-1093DAB3B73A}.Debug|x86.Build.0 = Debug|Win32 30 | {A0529565-FE5E-4E98-A9E0-1093DAB3B73A}.Release|x64.ActiveCfg = Release|x64 31 | {A0529565-FE5E-4E98-A9E0-1093DAB3B73A}.Release|x64.Build.0 = Release|x64 32 | {A0529565-FE5E-4E98-A9E0-1093DAB3B73A}.Release|x86.ActiveCfg = Release|Win32 33 | {A0529565-FE5E-4E98-A9E0-1093DAB3B73A}.Release|x86.Build.0 = Release|Win32 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | EndGlobal 39 | -------------------------------------------------------------------------------- /16th Study/src/expression/Array.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "SArray.hpp" 4 | #include "operators.hpp" 5 | 6 | template > 7 | class Array 8 | { 9 | private: 10 | Data data_; 11 | 12 | public: 13 | /* ---------------------------------------------------------- 14 | CONSTRUCTORS 15 | ---------------------------------------------------------- */ 16 | explicit Array(size_t s) 17 | : data_(s) 18 | { 19 | }; 20 | 21 | Array(const Data &obj) 22 | : data_(obj) 23 | { 24 | }; 25 | 26 | Array& operator=(const Array &obj) 27 | { 28 | assert(size() == obj.size()); 29 | for (size_t i = 0; i < size(); ++i) 30 | data_[i] = obj[i]; 31 | return *this; 32 | }; 33 | 34 | /* ---------------------------------------------------------- 35 | ACCESSORS 36 | ---------------------------------------------------------- */ 37 | size_t size() const 38 | { 39 | return data_.size(); 40 | }; 41 | 42 | Data& data() 43 | { 44 | return data_; 45 | }; 46 | const Data& data() const 47 | { 48 | return data_; 49 | }; 50 | 51 | inline T& operator[](size_t index) 52 | { 53 | assert(index < size()); 54 | return data_[index]; 55 | }; 56 | inline const T& operator[](size_t index) const 57 | { 58 | assert(index < size()); 59 | return data_[index]; 60 | }; 61 | }; 62 | 63 | template 64 | auto operator+(const Array &x, const Array &y) -> Array> 65 | { 66 | return Array> 67 | ( 68 | A_Add(x.data(), y.data()) 69 | ); 70 | } 71 | 72 | template 73 | auto operator*(const Array &x, const Array &y) -> Array> 74 | { 75 | return Array> 76 | ( 77 | A_Mult(x.data(), y.data()) 78 | ); 79 | } 80 | 81 | template 82 | auto operator*(T x, const Array &y) -> Array, D2>> 83 | { 84 | auto op = A_Mult, D2>(A_Scalar(x), y.data()); 85 | return Array, D2>>(op); 86 | } -------------------------------------------------------------------------------- /16th Study/src/variant/functional.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | /* =========================================================== 5 | META FUNCTIONS 6 | - BASE 7 | - ACCESSORS 8 | - MODIFIERS 9 | - FINDERS 10 | ============================================================== 11 | BASE 12 | ----------------------------------------------------------- */ 13 | // TYPE-LIST FOR POP 14 | template 15 | class TypeList {}; 16 | 17 | // MP - IF THEN ELSE 18 | template 19 | struct IfThenElseT 20 | { 21 | using Type = TrueType; 22 | }; 23 | 24 | template 25 | struct IfThenElseT 26 | { 27 | using Type = FalseType; 28 | }; 29 | 30 | template 31 | using IfThenElse = typename IfThenElseT::Type; 32 | 33 | /* ----------------------------------------------------------- 34 | ACCESSORS 35 | ----------------------------------------------------------- */ 36 | // FRONT 37 | //---- 38 | template 39 | class FrontT; 40 | 41 | template 42 | class FrontT> 43 | { 44 | public: 45 | using Type = Head; 46 | }; 47 | 48 | template 49 | using Front = typename FrontT::Type; 50 | 51 | //---- 52 | // AT 53 | //---- 54 | template 55 | struct TypeAt; 56 | 57 | template 58 | struct TypeAt, 0> 59 | { 60 | using Result = Head; 61 | }; 62 | 63 | template 64 | struct TypeAt, index> 65 | { 66 | using Result = typename TypeAt, index - 1>::Result; 67 | }; 68 | 69 | //---- 70 | // EMPTY 71 | //---- 72 | template 73 | class IsEmpty 74 | { 75 | public: 76 | static constexpr bool value = false; 77 | }; 78 | 79 | template<> 80 | class IsEmpty> { 81 | public: 82 | static constexpr bool value = true; 83 | }; 84 | 85 | /* ----------------------------------------------------------- 86 | MODIFIERS 87 | ----------------------------------------------------------- */ 88 | template 89 | class PopFrontT; 90 | 91 | template 92 | class PopFrontT> 93 | { 94 | public: 95 | using Type = TypeList; 96 | }; 97 | 98 | template 99 | using PopFront = typename PopFrontT::Type; 100 | 101 | /* ----------------------------------------------------------- 102 | FINDERS 103 | ----------------------------------------------------------- */ 104 | // TYPE TO INDEX 105 | template 106 | struct FindIndexOfT 107 | : public IfThenElse, T>::value, 108 | std::integral_constant, 109 | FindIndexOfT, T, N+1>> 110 | { 111 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C++ 템플릿 스터디 2 | 3 | 2018년 상반기에 진행하는 C++ 템플릿 스터디 관련 자료입니다. 4 | 5 | ## 날짜 6 | 7 | - 토요일 오전 10시 ~ 오후 1시 8 | 9 | ## 장소 10 | 11 | - 토즈 강남 지역 (강남 / 교대 / 양재 / 선릉) 12 | 13 | ## 스터디 인원 14 | 15 | - 13명 16 | 17 | ## 주 교재 18 | 19 | - C++ Templates: The Complete Guide (2nd Edition) 20 | 21 | ![Textbook](https://github.com/CppKorea/CppTemplateStudy/blob/master/Textbook.jpg) 22 | 23 | ## 일정 24 | 25 | - 1월 13일 26 | - 자기 소개 27 | - 스터디 진행 안내 28 | - 발표 순서 결정 29 | - 1월 20일 (발표자 : 남정호) 30 | - Chatper 1: Function Templates 31 | - Chapter 2: Class Templates 32 | - 1월 27일 33 | - 휴식 34 | - 2월 3일 (발표자 : 정승호) 35 | - Chapter 3: Nontype Template Parameters 36 | - Chapter 4: Variadic Templates 37 | - 2월 10일 (발표자 : 옥찬호) 38 | - Chapter 5: Tricky Basics 39 | - 2월 17일 40 | - 휴식 (설날 연휴) 41 | - 2월 24일 (발표자 : 옥찬호) 42 | - Chapter 6: Move Semantics and ```enable_if<>``` 43 | - Chapter 7: By Value or by Reference? 44 | - 3월 3일 (발표자 : 옥찬호, 배일섭) 45 | - Chapter 8: Compile-Time Programming 46 | - Chapter 9: Using Templates in Practice 47 | - Chapter 10: Basic Template Terminology 48 | - Chapter 11: Generic Libraries 49 | - 3월 10일 (발표자 : 김은재) 50 | - Chapter 12: Fundamentals in Depth 51 | - 3월 17일 52 | - 휴식 53 | - 3월 24일 (발표자 : 박동하) 54 | - Chapter 13: Names in Templates 55 | - Chapter 14: Instantiation 56 | - 3월 31일 (발표자 : Daniel) 57 | - Chapter 15: Template Argument Deduction 58 | - 4월 7일 (발표자 : 최두선) 59 | - Chapter 16: Specialization and Overloading 60 | - Chapter 17: Future Directions 61 | - 4월 14일 62 | - 휴식 63 | - 4월 21일 (발표자 : 정종채) 64 | - Chapter 18: The Polymorphic Power of Templates 65 | - Chapter 19: Implementing Traits 66 | - 4월 28일 (발표차 : 유원상) 67 | - Chapter 19: Implementing Traits 68 | - 5월 5일 69 | - 휴식 70 | - 5월 12일 71 | - 휴식 72 | - 5월 19일 (발표자 : 정은아) 73 | - Chapter 20: Overloading on Type Properties 74 | - Chapter 21: Templates and Inheritance 75 | - 5월 26일 (발표자 : 정은식) 76 | - Chapter 22: Bridging Static and Dynamic Polymorphism 77 | - Chapter 23: Metaprogramming 78 | - 6월 2일 79 | - 휴식 80 | - 6월 9일 (발표자 : 정원혁) 81 | - Chapter 24: Typelists 82 | - 6월 23일 (발표자 : 박동하) 83 | - Chapter 25: Tuples 84 | - 6월 30일 (발표자 : 남정호) 85 | - Chapter 26: Discriminated Unions 86 | - Chapter 27: Expression Templates 87 | - 7월 7일 (발표자 : 옥찬호) 88 | - Chapter 28: Debugging Templates, Appendixes 89 | - Appendix A: The One-Definition Rule 90 | - Appendix B: Value Categories 91 | - Appendix C: Overload Resolution 92 | - Appendix D: Standard Type Utilities 93 | - Appendix E: Concepts 94 | - 스터디 마무리 95 | - 비용 정산 96 | 97 | ## 스터디 참고 사항 및 진행 방식 98 | 99 | - 스터디에 사용하는 책은 개별 구입하셔야 합니다. 100 | - 각 조는 한 주에 해당하는 분량을 정리해 발표 자료를 만들어 발표합니다. 101 | - 발표 시간은 1시간 ~ 2시간입니다. 102 | - 발표 양식은 자유입니다. 103 | - 발표가 끝난 뒤 미리 정한 주제로 토론을 진행합니다. 104 | - 토론 시간은 1시간 내외입니다. 105 | - 스터디 이후에 발표 자료와 관련 예제 코드를 Github에 업로드합니다. 106 | 107 | ## 비용 108 | 109 | - 20만원 (예치금 3만원 + 장소 대여비 1만원 * 17회) 110 | 111 | ## 선납금 및 장소 대여비 입금 계좌 112 | 113 | - 신한은행 110-471-445816 옥찬호 114 | 115 | ## 스터디 진행 도우미 116 | 117 | - 박동하 118 | - 옥찬호 119 | - 정승호 120 | - 정은식 121 | -------------------------------------------------------------------------------- /16th Study/src/expression/SArray.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | template 6 | class SArray 7 | { 8 | private: 9 | T *data_; 10 | size_t size_; 11 | 12 | public: 13 | /* ---------------------------------------------------------- 14 | CONSTRUCTORS 15 | ---------------------------------------------------------- */ 16 | // CAPACITY CONSTRUCTOR 17 | explicit SArray(size_t size) 18 | : data_(new T[size]), 19 | size_(size) 20 | { 21 | init(); 22 | }; 23 | 24 | // COPY CONSTRUCTOR 25 | template 26 | SArray(const SArray &obj) 27 | : data_(new T[size]), 28 | size_(size) 29 | { 30 | copy(obj); 31 | }; 32 | 33 | template 34 | SArray& operator=(const SArray &obj) 35 | { 36 | copy(obj); 37 | return *this; 38 | }; 39 | 40 | // DESTRUCTOR 41 | ~SArray() 42 | { 43 | delete[] data_; 44 | }; 45 | 46 | protected: 47 | void init() 48 | { 49 | for (size_t i = 0; i < size(); ++i) 50 | data_[i] = T(); 51 | }; 52 | 53 | template 54 | void copy(SArray &obj) 55 | { 56 | assert(size() == obj.size()); 57 | for (size_t i = 0; i < size(); ++i) 58 | data_[i] = obj[i]; 59 | }; 60 | 61 | public: 62 | /* ---------------------------------------------------------- 63 | ACCESSORS 64 | ---------------------------------------------------------- */ 65 | size_t size() const 66 | { 67 | return size_; 68 | } 69 | 70 | T& operator[](size_t index) 71 | { 72 | return data_[index]; 73 | }; 74 | const T& operator[](size_t index) const 75 | { 76 | return data_[index]; 77 | }; 78 | 79 | /* ---------------------------------------------------------- 80 | SELF OPERATORS 81 | ---------------------------------------------------------- */ 82 | template 83 | SArray& operator+=(const SArray &obj) 84 | { 85 | assert(size() == obj.size()); 86 | for (size_t i = 0; i < obj.size(); ++i) 87 | data_[i] += obj[i]; 88 | return *this; 89 | }; 90 | 91 | template 92 | SArray& operator*=(const SArray &obj) 93 | { 94 | assert(size() == obj.size()); 95 | for (size_t i = 0; i < obj.size(); ++i) 96 | data_[i] *= obj[i]; 97 | return *this; 98 | }; 99 | 100 | template 101 | SArray& operator*=(const T &val) 102 | { 103 | for (size_t i = 0; i < a.size(); ++i) 104 | data_[i] *= val; 105 | return *this; 106 | }; 107 | }; 108 | 109 | template 110 | SArray operator+(const SArray &x, SArray &y) 111 | { 112 | assert(x.size() == y.size()); 113 | 114 | SArray ret(x.size()); 115 | for (size_t i = 0; i < x.size(); ++i) 116 | ret[i] = x[i] + y[i]; 117 | 118 | return ret; 119 | } 120 | 121 | template 122 | SArray operator*(const SArray &x, SArray &y) 123 | { 124 | assert(x.size() == y.size()); 125 | 126 | SArray ret(x.size()); 127 | for (size_t i = 0; i < x.size(); ++i) 128 | ret[i] = x[i] * y[i]; 129 | 130 | return ret; 131 | } 132 | 133 | template 134 | SArray operator*(const X &val, SArray &elems) 135 | { 136 | SArray ret(elems.size()); 137 | for (size_t i = 0; i < elems.size(); ++i) 138 | ret[i] = val * elems[i]; 139 | 140 | return ret; 141 | } -------------------------------------------------------------------------------- /16th Study/src/expression/expression.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {A0529565-FE5E-4E98-A9E0-1093DAB3B73A} 24 | Win32Proj 25 | expression 26 | 10.0.15063.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v141 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v141 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v141 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v141 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | 88 | 89 | Level3 90 | Disabled 91 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | 93 | 94 | Console 95 | 96 | 97 | 98 | 99 | 100 | 101 | Level3 102 | Disabled 103 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 104 | 105 | 106 | Console 107 | 108 | 109 | 110 | 111 | Level3 112 | 113 | 114 | MaxSpeed 115 | true 116 | true 117 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 118 | 119 | 120 | Console 121 | true 122 | true 123 | 124 | 125 | 126 | 127 | Level3 128 | 129 | 130 | MaxSpeed 131 | true 132 | true 133 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 134 | 135 | 136 | Console 137 | true 138 | true 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /16th Study/src/variant/variant.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {96150404-C730-4A8E-B912-BA33083AA7C5} 24 | Win32Proj 25 | variant 26 | 10.0.15063.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v141 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v141 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v141 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v141 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | 88 | 89 | Level3 90 | Disabled 91 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | 93 | 94 | Console 95 | 96 | 97 | 98 | 99 | 100 | 101 | Level3 102 | Disabled 103 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 104 | 105 | 106 | Console 107 | 108 | 109 | 110 | 111 | Level3 112 | 113 | 114 | MaxSpeed 115 | true 116 | true 117 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 118 | 119 | 120 | Console 121 | true 122 | true 123 | 124 | 125 | 126 | 127 | Level3 128 | 129 | 130 | MaxSpeed 131 | true 132 | true 133 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 134 | 135 | 136 | Console 137 | true 138 | true 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /7th Study/Chap14.md: -------------------------------------------------------------------------------- 1 | 2 | 18/03/24 진행: [박동하](https://github.com/luncliff) luncliff@gmail.com 3 | 4 | # Chapter 14: 실체화 5 | > Instantiation 6 | 7 | C++ 템플릿의 실체화는 기본적이지만 꽤 복잡미묘합니다. 8 | 그 이유 중 하나는, 템플릿을 통해 생성된 개체들이 소스 코드 상의 한 곳에 위치하는게 아니기 때문입니다. 9 | 10 | 템플릿의 위치, 템플릿이 사용된 위치, 템플릿 인자가 정의된 위치 모두 고려되어야 합니다. 11 | 12 | ## 1. 필요에 의한 실체화 13 | > On-Demand Instantiation 14 | 15 | 템플릿 특수화가 사용되면, C++ 컴파일러는 템플릿 인자들을 치환하여 특수화를 생성합니다. _implicit_ 혹은 _automatic_ 실체화라고도 합니다. 16 | 17 | 이 말은, C++ 컴파일러가 템플릿의 선언 뿐만 아니라 전체의 정의를 필요로 한다는 말이기도 합니다. 18 | 19 | ```c++ 20 | template 21 | class C; // #1 템플릿 선언 22 | 23 | C*p = 0; // #2 포인터. 아직 정의가 필요하지는 않음 24 | 25 | template 26 | class C{ 27 | public: 28 | void f(); // #3 멤버 함수 선언 29 | }; // #4 클래스 템플릿 정의 완료 30 | 31 | void g(C& c) // #5 레퍼런스. 32 | // 포인터와 동일하게 클래스 템플릿 선언만 사용 33 | { 34 | c.f(); // #6 멤버함수 호출. 35 | // 이때는 클래스 템플릿 정의를 사용한다 36 | // C::f()의 정의가 필요 37 | } 38 | 39 | // #6에서 필요로 했던 정의 40 | template 41 | void C::f() 42 | { 43 | // ... 44 | } 45 | ``` 46 | 47 | 요컨대, 클래스의 크기가 필요하거나 멤버에 접근하는 경우 전체 정의가 필요합니다. 클래스의 크기에 대해선, 아래와 같은 코드를 예로 들 수 있습니다. 48 | ```c++ 49 | C* p = new C{}; 50 | ``` 51 | `operator new()`는 메모리 할당을 위해 크기를 알아야 하기 때문에, 템플릿 클래스 `C`의 `void` 특수화에 대한 정의가 필요하게 됩니다. 52 | 53 | 특히 #6과 같은 경우엔, 함수 `g` 에서 `C::f()`를 볼 수 있고(visible), 에 접근할 수 있는지 확인할 수 있어야 합니다(`private`, `protected`). 54 | 55 | ## 2. 게으른 실체화 56 | > Lazy Instantiation 57 | 58 | 이 경우는 템플릿이 아닌 C++ 클래스를 사용하는 것과 다르지 않습니다. 많은 경우 클래스 타입은 _완전해야(complete)_ 하기 때문에, 컴파일러는 클래스 템플릿 정의로부터 완전한 클래스 코드를 생성해냅니다. 59 | 60 | ### 2.1 부분/전체 실체화 61 | > Partial and Full Instantiation 62 | 63 | 모든 경우에 컴파일러가 클래스/함수 전체에 대한 정의를 치환해야 하는 것은 아닙니다. 예를들어, 64 | 65 | ```c++ 66 | template 67 | T f(T p){ 68 | return 2*p; 69 | } 70 | 71 | decltye(f(2)) x = 2; 72 | ``` 73 | 변수 `x`를 선언하는 부분에서는 `f()`의 전체 정의가 필요한 것은 아닙니다. `f()`의 선언만 치환하게 됩니다. 이를 부분 실체화(partial instantiation)이라고 합니다. 74 | 75 | 클래스 템플릿도 이와 유사합니다. 76 | ```c++ 77 | template 78 | class Q 79 | { 80 | using Type = typename T::Type; 81 | }; 82 | 83 | Q* p = 0; // OK: Q의 몸체는 치환되지 않습니다. 84 | ``` 85 | 이 경우, `int`는 `::Type`을 정의하지 않기 때문에, 템플릿 전체가 치환된다면 에러가 발생할 것입니다. 하지만 이 예제에서는 완전할 필요가 없고, 때문에 이 코드는 허용됩니다. 86 | 87 | C++ 에서 "템플릿 실체화"라는 용어가 쓰인다면 보통은 전체 실체화(full instantiation)를 의미합니다. 88 | 89 | ### 2.2 Instantiated Components 90 | 91 | 템플릿이 실체화될 때는, 각 멤버의 '선언'이 실체화됩니다. 달리 말해, '정의'는 실체화되지 않습니다. 92 | 93 | ```c++ 94 | template 95 | class Safe { 96 | }; 97 | 98 | template 99 | class Danger { 100 | int arr[N]; // N이 음수가 아닌 한 문제 없다... 101 | }; 102 | 103 | template 104 | class Tricky { 105 | public: 106 | void noBodyHere(Safe = 3); // OK: 실제로 호출되지만 않는다면... 107 | 108 | void inclass(){ // OK: 정의는 나중에 호출할 떄 생성된다. 109 | // 그 시점에 N<=0 이면 에러가 된다. 110 | Danger noBoomYet; 111 | } 112 | 113 | struct Nested 114 | { 115 | Danger pfew; // OK: Nested가 사용되지 않고 N이 양수라면 문제 없다. 116 | }; 117 | 118 | union{ 119 | Danger anonymous; // OK: Tricky가 N<=0 에서 *실체화*되지 않는 한 문제 없다. 120 | int align; 121 | }; 122 | 123 | void unsafe(T (*p)[N]); // OK: Tricky가 N<=0 으로 *실체화*되지 않는 한 문제 없다. 124 | 125 | void error(){ 126 | Danger<-1> boom; // ERROR: 언제나 에러. 127 | } 128 | } 129 | ``` 130 | 131 | C++ 컴파일러가 템플릿의 문법과 보통의 문맥적 제약을 확인할 떄는, "최선의 경우"를 전제합니다. 예를 들면, `Danger::arr`의 길이는 0 혹은 음수가 될 수 있지만, 그렇지 않을 것이라고 전제합니다. 132 | 133 | ## 3. C++의 실체화 모델 134 | > The C++ Instantiation Model 135 | 136 | 템플릿의 실체화 과정은 템플릿 개체로부터 타입, 함수, 또는 변수를 얻어오는 과정이라고 할 수 있습니다. 직관적인 것 같지만, 실제로는 명확하게 정의되어야 하는 부분들이 있죠. 137 | 138 | ### 3.1 2단계 탐색 139 | > Two Phase Lookup 140 | 141 | 13장에서 템플릿 인자에 따라 달라지는 타입들은 템플릿 구문분석 단계에서는 확인할 수 없다는 것을 확인했습니다. 대신, 이 타입들은 실체화 지점에서 다시 한번 탐색하게 됩니다. 템플릿 인자와 무관한 경우라면, 탐색을 일찍 수행해서 템플릿이 처음 확인된 순간에 에러를 찾아냅니다. 142 | 143 | 144 | 1. 템플릿 구문분석(Parsing) 145 | 1. 템플릿 실체화(Instantiation) 146 | 147 | 148 | 템플릿을 분석할 때는, 템플릿 인자와 무관한 이름들을 먼저 탐색합니다. 이때는 unqualified dependent name들이 탐색됩니다. 탐색에는 Ordinary Lookup 규칙을 사용합니다. 적용할 수 있다면, ADL 역시 적용합니다. (즉, ) 149 | 150 | 템플릿을 실체화 할 때는, 실체화 지점(Point Of Instantiation)에서 탐색을 수행합니다. 이때는 dependent qualified name을 탐색하게 됩니다. 앞서 Parsing 단계에서 찾지 못한 unqualified dependent name에 대해서는 ADL을 수행하게 됩니다. 151 | 152 | ```c++ 153 | namespace N{ 154 | template void g(){} 155 | enum E { e }; 156 | } 157 | 158 | template void f(){} 159 | 160 | template void h(T P){ 161 | f(p); // #1 162 | g(p); // #2 ERROR 163 | } 164 | 165 | int main(){ 166 | h(N::e); // 템플릿 함수 호출. T == N::E 167 | } 168 | ``` 169 | #### Phase 1 170 | `f()`를 분석하는 과정에서 `f()`가 템플릿의 이름인지를 확인합니다. 템플릿인 경우 에러는 발생하지 않습니다. 같은 원리로 `g()`는 템플릿 함수인지 확인할 수 없기 때문에 `g`를 따라오는 `<`는 less-than으로 인식됩니다. 171 | 172 | #### Phase 2 173 | 사실 `h()`가 1단계에서 에러없이 분석되면, `main`에서의 호출은 ADL로 이어지고, `N::g()`를 탐색하는데 성공하게 됩니다. 174 | 175 | 176 | ### 3.2 실체화 지점 177 | > Points of Instantiation 178 | 179 | 템플릿의 POI는 인자가 치환되면서 생성된 코드가 삽입될 수 있는 지점을 의미합니다. 다수의 POI가 전부 사용되는 것은 아닙니다. One Definition Rule에 따라서, 컴파일러는 생성된 POI 중 하나를 선택하고, 바로 그 지점에 코드를 생성하게 됩니다. 180 | 181 | #### 함수 템플릿 182 | 함수 템플릿의 POI는 가장 가까운 네임스페이스 범위 선언 혹은 함수 템플릿을 참조한 정의의 **바로 뒤**에 생성됩니다. 아래 예제코드에서는 #4에 해당합니다. 183 | 184 | ```c++ 185 | class MyInt 186 | { 187 | public MyInt(int i); 188 | }; 189 | 190 | MyInt operator -(MyInt const&); 191 | 192 | bool operator > (MyInt const&, MyInt const&); 193 | 194 | using Int = MyInt; 195 | 196 | template 197 | void f(T i){ 198 | if(i>0){ 199 | g(-1); 200 | } 201 | } 202 | // #1 203 | void g(Int) 204 | { 205 | // #2 206 | f(42); // point of call 207 | // #3 208 | } 209 | // #4 : 함수 템플릿을 참조한 정의의 바로 뒤 210 | ``` 211 | 212 | #### 클래스 템플릿 213 | 214 | 클래스 템플릿의 POI는 가장 가까운 네임스페이스 범위 선언 혹은 클래스 템플릿을 참조한 정의의 **바로 앞**에 생성됩니다. 아래 예제 코드에서는 #1에 해당합니다. 215 | 216 | ```c++ 217 | template 218 | class S { 219 | public: 220 | using I = int; 221 | }; 222 | 223 | // #1 : 클래스 템플릿을 참조한 정의의 바로 앞 224 | template 225 | void f() 226 | { 227 | S::I var1 = 41; 228 | typename S::I var2 = 42; 229 | } 230 | 231 | int main() 232 | { 233 | f(); 234 | } 235 | // #2 236 | // #2a 237 | // #2b 238 | ``` 239 | 240 | 클래스 템플릿의 경우, 두번째 이후로 생성된 POI는 Primary POI의바로 앞에 배치됩니다. `#2`에 `f()`의 POI가 생성되면, `S`의 POI가 결정되어야 하는데, 이때 `S`의 Primary POI는 `f()`의 POI입니다. 241 | 242 | - `#1`: `S`의 POI 243 | - `#2` 244 | - `#2a`: `S`의 POI 245 | - `#2b`: `f()`의 POI. `S`의 Primary POI 246 | 247 | 248 | ### 3.3 포함 모델 249 | > The Inclusion Model 250 | 251 | 현재 C++에서는 이 모델만을 사용하고 있는데, 간단히 말해 `#include`를 사용해 템플릿 코드가 모든 translation unit에서 볼 수 있도록 만드는 것입니다. 252 | 253 | ## 4. 구현 방법들 254 | > Implementation Schemes 255 | 256 | Instantiation 전략에 대해서... 257 | 258 | ### 4.1 탐욕적 전략 259 | > Greedy Instantiation 260 | 261 | ### 4.2 조회 전략? 262 | > Queried Instantiation 263 | 264 | ### 4.3 되풀이 전략 265 | > Iterated Instantiation 266 | 267 | ## 5. 명시적 실체화 268 | > Explicit Instantiation 269 | 270 | 템플릿 특수화의 POI를 명시적으로 생성하는 것도 가능합니다. 271 | 272 | ```c++ 273 | template 274 | void f(T) 275 | { 276 | 277 | } 278 | 279 | // 4가지 명시적 실체화 280 | template void f(); 281 | template void f<>(float); 282 | template void f(long); 283 | template void f(char); 284 | ``` 285 | 예제의 4가지 모두 유효한 방법입니다. 클래스 템플릿의 멤버들도 이 방법을 사용해서 실체화할 수 있습니다. 286 | 287 | ```c++ 288 | template 289 | class S{ 290 | public: 291 | void f(){ 292 | // ... 293 | } 294 | }; 295 | 296 | template void S::f(); 297 | template class S; 298 | ``` 299 | 특수화된 클래스 템플릿을 실체화시킬 경우 모든 멤버에 특수화를 적용할 수 있습니다. 300 | 301 | 명시적으로 실체화된 템플릿은, 명시적으로 특수화되어서는 안됩니다. 그 반대도 마찬가지입니다. 이는 One Definition Rule을 위반하기 때문이죠. 302 | 303 | ### 5.1 수동 선언 304 | > Manual Instantiation 305 | 306 | ### 5.2 명시적 실체화의 선언 307 | > Explicit Instantiation Declarations 308 | -------------------------------------------------------------------------------- /16th Study/26. Discriminated Unions.md: -------------------------------------------------------------------------------- 1 | # 26. Discriminated Unions 2 | ## 들어가기 전에 3 | ### `Variant` 4 | 우리는 그간 `Tuple` 을 직접 구현해 보았다. `Tuple` 은 템플릿으로 구현된 일련의 구조체 (`struct`) 인데, 그렇다면 공용체 (`union`) 를 템플릿으로 구현한 객체는 무엇이 있을까? 5 | 6 | ![struct vs union](images/struct_vs_union.png) 7 | 8 | ```cpp 9 | struct | union 10 | { 11 | char a; // 1 12 | short b; // 2 13 | long c; // 4 14 | long long d; // 8 15 | } 16 | 17 | // sizeof(struct) = SUM(sizeof(...members)) + å 18 | // sizeof(union) = MAX(sizeof(...members)) 19 | ``` 20 | 21 | > `Variant` 가 바로 그 공용체를 템플릿으로 구현한 객체이며, 우리는 26 장에서는 바로 그 `Variant` 를 구현해 볼 것이다. 22 | 23 | 24 | 25 | ## 26.1. Storage 26 | ### Variant 27 | 제일 먼저 해야 할 것은, 데이터를 어떻게 저장하느냐다. 28 | - 데이터 저장소: `data_` 29 | - 데이터 타입: `index_` 30 | 31 | ```cpp 32 | template 33 | class Variant 34 | { 35 | private: 36 | Tuple data_; 37 | size_t index_; 38 | } 39 | ``` 40 | 41 | 만일 데이터를 위와 같이 `Tuple` 또는 그와 유사한 모종의 구조체에 입력케 되면, 불필요한 메모리 낭비가 생기게 된다. 따라서 `struct` 가 아닌, `union` 에 기반한 데이터 저장소가 필요하다. 42 | 43 | ```cpp 44 | //---- 45 | // STRUCT 46 | //---- 47 | template 48 | struct Tuple; 49 | 50 | template 51 | struct Tuple 52 | { 53 | private: 54 | Head head_; 55 | Tuple tail_; 56 | } 57 | 58 | template <> 59 | struct Tuple<> {}; 60 | 61 | //---- 62 | // UNION 63 | //---- 64 | template 65 | union VariantStorage; 66 | 67 | template 68 | union VariantStorage 69 | { 70 | private: 71 | Head head_; 72 | VariantStorage tail_; 73 | } 74 | 75 | template <> 76 | union VariantStorage<> {}; 77 | ``` 78 | 79 | 앞서의 이유로 (불필요한 메모리 낭비를 막기 위하여) `template union` 객체인 `VariantStorage` 를 만들었다. 지금 만드려는 `VariantStorage` 와, 우리가 지난 시간에 만들었던 `Tuple` 이 어떻게 다른지 보자. 80 | 81 | 차이점이라고는 단지 `union` 을 사용했냐, `struct` 를 사용했냐 뿐이다. 82 | 83 | 84 | 85 | ## 26.2. Design 86 | ### Definitions 87 | ```cpp 88 | template 89 | class Variant 90 | { 91 | private: 92 | VariantStorage data_; 93 | size_t index_; 94 | 95 | public: 96 | // CONSTRUCTORS 97 | Variant(); 98 | template Variant(const T&); 99 | 100 | // ACCESSORS 101 | template bool is() const; 102 | template auto get() const; 103 | template auto get() const; 104 | 105 | // VISITOR 106 | template 107 | void visit(Function&&) const; 108 | }; 109 | ``` 110 | 111 | 우리가 만들 `Variant` 클래스의 인터페이스는 이와 같다. 112 | 113 | ### FindIndexOfT 114 | ```cpp 115 | template 116 | struct FindIndexOfT 117 | : public IfThenElse, T>::value, 118 | std::integral_constant, 119 | FindIndexOfT, T, N+1>> 120 | { 121 | }; 122 | ``` 123 | 124 | 또한, `Variant` 를 구현키 위해 새로운 종류의 템플릿 객체 `FindIndexOfT` 가 필요하다. 125 | 126 | `FindIndexOfT` 객체는 내가 찾고자 하는 타입 `T` 가 `TypeList` 의 몇 번째 타입에 해당하는 지 검색해준다. `FindIndexOfT` 는 `IfThenElse` 를 이용 (상속), 재귀적으로 타입 `T` 의 `index` 번호를 탐색해나간다. 127 | 128 | ### Meta Programming 129 | `FindIndexOfT` 및 `Variant` 구현을 위해서는 몇 가지 템플릿 객체들이 필요하다. 분명 과거에 구현했던 객체들이지만, 복습하는 셈 치고 다시 한 번 더 보자. 130 | 131 | ```cpp 132 | /* =========================================================== 133 | UTILITIES 134 | - BASE 135 | - ACCESSORS 136 | - MODIFIERS 137 | ============================================================== 138 | BASE 139 | ----------------------------------------------------------- */ 140 | // TYPE-LIST FOR POP 141 | template 142 | class TypeList {}; 143 | 144 | // MP - IF THEN ELSE 145 | template 146 | struct IfThenElseT 147 | { 148 | using Type = TrueType; 149 | }; 150 | 151 | template 152 | struct IfThenElseT 153 | { 154 | using Type = FalseType; 155 | }; 156 | 157 | template 158 | using IfThenElse = typename IfThenElseT::Type; 159 | 160 | /* ----------------------------------------------------------- 161 | ACCESSORS 162 | ----------------------------------------------------------- */ 163 | // FRONT 164 | //---- 165 | template 166 | class FrontT; 167 | 168 | template 169 | class FrontT> 170 | { 171 | public: 172 | using Type = Head; 173 | }; 174 | 175 | template 176 | using Front = typename FrontT::Type; 177 | 178 | //---- 179 | // AT 180 | //---- 181 | template 182 | struct TypeAt; 183 | 184 | template 185 | struct TypeAt, 0> 186 | { 187 | using Result = Head; 188 | }; 189 | 190 | template 191 | struct TypeAt, index> 192 | { 193 | using Result = typename TypeAt, index - 1>::Result; 194 | }; 195 | 196 | /* ----------------------------------------------------------- 197 | MODIFIERS 198 | ----------------------------------------------------------- */ 199 | template 200 | class PopFrontT; 201 | 202 | template 203 | class PopFrontT> 204 | { 205 | public: 206 | using Type = TypeList; 207 | }; 208 | 209 | template 210 | using PopFront = typename PopFrontT::Type; 211 | ``` 212 | 213 | 214 | 215 | ## 26.3. Value Query and Extraction 216 | ### Access by `Type` 217 | ```cpp 218 | template 219 | bool Variant::is() const 220 | { 221 | constexpr size_t N = FindIndexOfT, T>::value; 222 | return (this->index_ == N); 223 | } 224 | 225 | template 226 | auto Variant::get() const 227 | { 228 | constexpr size_t N = FindIndexOfT, T>::value; 229 | return this->get(); 230 | } 231 | ``` 232 | 233 | `FindIndexOfT` 를 통하여, 타입 `T` 가 몇 번째 타입인지 알아낸 후, 해당 `index` 를 통하여 원소에 액세스 한다. 234 | 235 | ### Access by `Index` 236 | ```cpp 237 | template 238 | struct VariantGetter 239 | { 240 | template 241 | static auto apply(const Data &obj) 242 | { 243 | return VariantGetter::apply(obj.tail_); 244 | }; 245 | }; 246 | 247 | template <> 248 | struct VariantGetter<0> 249 | { 250 | template 251 | static auto apply(const Data &obj) 252 | { 253 | return obj.head_; 254 | }; 255 | }; 256 | 257 | template 258 | auto Variant::get() const 259 | { 260 | return VariantGetter::apply(data_); 261 | } 262 | ``` 263 | 264 | 어디서 많이 봤던 코드가 아닌가? 그렇다. `Index` 번호로 원소에 접근하는 방법은 지난 시간에 `TupleGetter` 를 구현하면서 다뤘었다. 오늘의 `VariantGetter` 는 그 때의 `TupleGetter` 코드와 정확히 같다. 265 | 266 | 267 | 268 | ## 26.4. Element Initialization, Assignment and Destruction 269 | ### `VariantStorage.hpp` 270 | ```cpp 271 | template 272 | union VariantStorage; 273 | 274 | template 275 | union VariantStorage 276 | { 277 | public: 278 | Head head_; 279 | VariantStorage tail_; 280 | 281 | public: 282 | // DO ITSELF 283 | VariantStorage() {}; 284 | VariantStorage(const Head &head) 285 | : head_(head) {}; 286 | 287 | // SHIFT RESPONSIBILITY TO TAIL 288 | template 289 | VariantStorage(const T &val) 290 | : tail_(val) {}; 291 | }; 292 | 293 | template<> 294 | union VariantStorage<> 295 | { 296 | }; 297 | ``` 298 | 299 | `VariantStorage` 는 `Variant` 의 실질적 데이터 저장소이자 템플릿 공용체로써, 재귀적 관계를 통하여 각 타입을 저장하고 있다. 300 | 301 | 할당받은 데이터의 타입이 `Head` 이거든 현재의 객체에 할당하며, `Head` 가 아닌 그 외의 다른 타입이거든 (`T`), 자식 객체 (`VariantStorage tail_) 에게 데이터 할당의 역할을 넘긴다. 302 | 303 | ### `Variant.hpp` 304 | ```cpp 305 | template 306 | class Variant 307 | { 308 | private: 309 | VariantStorage data_; 310 | size_t index_; 311 | 312 | public: 313 | // DEFAULT CONSTRUCTOR - UNDEFINED 314 | Variant() 315 | : index_(-1) {}; 316 | 317 | // ASSIGN CONSTRUCTOR - SPECIFIC TYPE & VALUE 318 | template 319 | Variant(const T &val) 320 | : data_(val), 321 | index_(FindIndexOfT, T>::value) 322 | { 323 | }; 324 | }; 325 | ``` 326 | 327 | 실질적인 데이터 저장은 `VariantStorage` 가 하고 있다. 고로, *Assign Constructor* 를 통해 객체가 생성되거든, 할당받은 데이터를 `VariantStorage` 에 넘겨주며, `FindIndexOfT` 를 통하여 현재 할당받은 데이터의 타입 `T` 가 몇 번째 타입인 지 기록해두자. 328 | 329 | 330 | 331 | ## 26.5. Visitors 332 | ```cpp 333 | template 334 | class Variant 335 | { 336 | public: 337 | template 338 | void visit(Func &&func) const 339 | { 340 | if (index_ == -1) 341 | throw std::invalid_argument("value is not assigned."); 342 | 343 | _Visit(&func); 344 | }; 345 | 346 | private: 347 | template 348 | void _Visit(Func *func) const 349 | { 350 | if (is()) 351 | (*func)(get()); 352 | else if constexpr (sizeof...(Tail) > 0) 353 | _Visit(func); 354 | }; 355 | }; 356 | ``` 357 | 358 | 359 | 360 | ## 26.6. Variant Initialization and Assignment 361 | Nothing to do 362 | -------------------------------------------------------------------------------- /16th Study/27. Expression Templates.md: -------------------------------------------------------------------------------- 1 | # 27. Expression Templates 2 | ## 들어가면서 3 | ```cpp 4 | Array x(1000), y(1000); 5 | ... 6 | x = 1.2*x + x*y; 7 | ``` 8 | 9 | Numeric Array 의 operator 를 템플릿을 이용해 효율적으로 구현해보자. 10 | 11 | 12 | 13 | ## 27.1. Temporaries and Split Loops 14 | ### `SArray` 15 | ```cpp 16 | #include 17 | #include 18 | 19 | template 20 | class SArray 21 | { 22 | private: 23 | T *data_; 24 | size_t size_; 25 | 26 | public: 27 | /* ---------------------------------------------------------- 28 | CONSTRUCTORS 29 | ---------------------------------------------------------- */ 30 | // CAPACITY CONSTRUCTOR 31 | explicit SArray(size_t size) 32 | : data_(new T[size]), 33 | size_(size) 34 | { 35 | init(); 36 | }; 37 | 38 | // COPY CONSTRUCTOR 39 | template 40 | SArray(const SArray &obj) 41 | : data_(new T[size]), 42 | size_(size) 43 | { 44 | copy(obj); 45 | }; 46 | 47 | template 48 | SArray& operator=(const SArray &obj) 49 | { 50 | if (&orig != this) 51 | copy(orig); 52 | return *this; 53 | }; 54 | 55 | // DESTRUCTOR 56 | ~SArray() 57 | { 58 | delete[] data_; 59 | }; 60 | 61 | protected: 62 | void init() 63 | { 64 | for (size_t i = 0; i < size(); ++i) 65 | data_[i] = T(); 66 | }; 67 | 68 | template 69 | void copy(SArray &obj) 70 | { 71 | assert(size() == obj.size()); 72 | for (size_t i = 0; i < size(); ++i) 73 | data_[i] = obj[i]; 74 | }; 75 | 76 | public: 77 | /* ---------------------------------------------------------- 78 | ACCESSORS 79 | ---------------------------------------------------------- */ 80 | size_t size() const 81 | { 82 | return size_; 83 | } 84 | 85 | T& operator[](size_t index) 86 | { 87 | return data_[index] 88 | };; 89 | const T& operator[](size_t index) const 90 | { 91 | return data_[index]; 92 | }; 93 | }; 94 | ``` 95 | 96 | 평범한 Numeric Array 클래스인 `SArray` 를 간단히 구현해 보았다. 97 | 98 | 이제 여기에 연산자 함수를 추가해보자. 99 | 100 | ### Global Operand Functions 101 | ```cpp 102 | template 103 | SArray operator+(const SArray &x, SArray &y) 104 | { 105 | assert(a.size() == b.size()); 106 | 107 | SArray ret(a.size()); 108 | for (size_t i = 0; i < a.size(); ++i) 109 | ret[i] = x[i] + y[i]; 110 | 111 | return ret; 112 | } 113 | 114 | template 115 | SArray operator*(const SArray &x, SArray &y) 116 | { 117 | assert(a.size() == b.size()); 118 | 119 | SArray ret(a.size()); 120 | for (size_t i = 0; i < a.size(); ++i) 121 | ret[i] = x[i] * y[i]; 122 | 123 | return ret; 124 | } 125 | 126 | template 127 | SArray operator*(const X &val, SArray &elems) 128 | { 129 | SArray ret(elems.size()); 130 | for (size_t i = 0; i < a.size(); ++i) 131 | ret[i] = val * elems[i]; 132 | 133 | return ret; 134 | } 135 | ``` 136 | 137 | 위 코드와 같이 `SArray` 에 대한 연산자 함수를 구현하였다. 이 연산자 함수들를 가지고 다음 코드를 실행하면 어떻게 될까? 138 | 139 | ```cpp 140 | SArray x(100), y(100); 141 | ... 142 | SArray ret = 1.2*x + x*y; 143 | 144 | // tmp1 = 1.2 * x; 145 | // tmp2 = x * y; 146 | // tmp3 = tmp1 + tmp2; 147 | 148 | // ret = tmp1 + tmp3; 149 | ``` 150 | 151 | 불필요한 복사 연산이 너무 많이 이루어졌다. `z = 1.2*x + x*y` 라는 간단한 수식을 계산키 위하여, 복사 연산이 무려 네 번에 걸쳐 이루어진 것이다. 152 | 153 | 뭔가 복사 연산을 줄일 수 있는 방법은 없을까? 154 | 155 | ### Self Operand Methods 156 | ```cpp 157 | template 158 | class SArray 159 | { 160 | public: 161 | template 162 | SArray& operator+=(const SArray &obj) 163 | { 164 | assert(a.size() == b.size()); 165 | for (size_t i = 0; i < a.size(); ++i) 166 | data_[i] += obj[i]; 167 | return *this; 168 | }; 169 | 170 | template 171 | SArray& operator*=(const SArray &obj) 172 | { 173 | assert(a.size() == b.size()); 174 | for (size_t i = 0; i < a.size(); ++i) 175 | data_[i] *= obj[i]; 176 | return *this; 177 | }; 178 | 179 | template 180 | SArray& operator*=(const T &val) 181 | { 182 | for (size_t i = 0; i < a.size(); ++i) 183 | data_[i] *= val; 184 | return *this; 185 | }; 186 | }; 187 | ``` 188 | 189 | 불필요한 복사 연산을 줄이고자 `SArray` 클래스에 연산자 메소드를 구현하였다. 190 | 191 | ```cpp 192 | // ret = 1.2*x + x*y 193 | SArray x(100), y(100); 194 | ... 195 | 196 | SArray tmp1 = x; tmp1 *= 1.2; 197 | SArray tmp2 = x; tmp2 *= y; 198 | SArray ret = tmp1; ret += tmp2; 199 | ``` 200 | 201 | 하지만, 이렇게 내부 연산자를 사용하면 코드가 복잡해질 뿐더러 (가독성이 떨어지며), 경우에 따라, 사칙연산 우선순위에 등에 의해, 복사 연산은 여전히 수행될 수 있다. 202 | 203 | 204 | 205 | ## 27.2. Encoding Expressions in Template Arguments 206 | 앞서 `SArray` 클래스 구현체에서 보듯이, 일반적인 방법으로는 도저히 Numeric Array 의 효율적인 연산함수 구현이 가능치 않았다. 207 | 208 | ```cpp 209 | std::vector x(100), y(100); 210 | ... 211 | 212 | std::vector ret(100); 213 | for (size_t i = 0; i < x.size(); ++i) 214 | ret[i] = 1.2*x[i] + x[i]*y[i]; 215 | ``` 216 | 217 | 지금부터 템플릿 프로그래밍을 통해 위 코드 수준의 퍼포먼스를 보여주는 Numeric Array 를 만들어보자. 우리가 이번에 만들 템플릿 연산자 함수는, 아래와 같은 형태를 띄게 될 것이다. 218 | 219 | > ```cpp 220 | > A_Add,Array>, A_Mult,Array>> 221 | > ``` 222 | 223 | ### 27.2.1. Operands of the Expression Templates 224 | #### Operator Templates 225 | ```cpp 226 | template 227 | class A_Operator 228 | { 229 | public: 230 | typename A_Traits::Reference x_; 231 | typename A_Traits::Reference y_; 232 | 233 | public: 234 | A_Operator(const X &x, const Y &y) 235 | : x_(x), y_(y) 236 | { 237 | }; 238 | 239 | auto operator[](size_t index) const 240 | { 241 | return Operator()(x_[index], y_[index]); 242 | }; 243 | 244 | size_t size() const 245 | { 246 | // SIZE 0 FOR SCALAR 247 | assert(x_.size() == 0 || y_.size() == 0 || x_.size() == y_.size()); 248 | return x_.size() != 0 249 | ? x_.size() 250 | : y_.size(); 251 | }; 252 | }; 253 | 254 | template 255 | using A_Add = A_Operator>; 256 | 257 | template 258 | using A_Mult = A_Operator>; 259 | ``` 260 | 261 | 제일 먼저, 공용 연산자에 해당하는 `A_Operator` 를 만들자. 그리고 `Operator` 를 특정하여 `alias`: `A_Add` 와 `A_Mult` 를 만들어준다. (원한다면 `A_Minus`, `A_Divide` 도 다 만들어낼 수 있다.) 262 | 263 | 그리고 템플릿 파라미터 (argument) `Operator` 와 메소드 `operator[]` 가 무슨 역할을 하는지 이해하면, 오늘 우리가 무엇을 통하여 Numeric Array 를 최적화 하고자 하는지 쉬이 알 수 있을 것이다. 264 | 265 | > ```cpp 266 | > using F1 = A_Operator>; 267 | > using F2 = A_Operator>; 268 | > using F3 = A_Operator>; 269 | > 270 | > // (X + Y) * (X * Y) 271 | > // operator[](X, Y) 를 통하여 별도의 복사연산 없이 단 번에 이루어진다. 272 | ``` 273 | 274 | #### Reference Templates 275 | ```cpp 276 | template 277 | class A_Traits 278 | { 279 | public: 280 | using Reference = const T&; 281 | }; 282 | 283 | template 284 | class A_Scalar 285 | { 286 | private: 287 | const T &s; 288 | 289 | public: 290 | constexpr A_Scalar(const T &v) 291 | : s(v) 292 | { 293 | }; 294 | 295 | constexpr size_t size() const 296 | { 297 | return 0; 298 | }; 299 | 300 | constexpr const T& operator[](size_t) const 301 | { 302 | return s; 303 | }; 304 | }; 305 | ``` 306 | 307 | 앞서 구현했던 `A_Operator` 를 위한 템플릿 traits 클래스인 `A_Traits` 와 `A_Scalar` 를 만들어주었다. 특히 `A_Scalar` 는 `A_Operator.operator[](size_t)` 를 위하여 배열의 인터페이스를 흉내내기 위한 전형적인 wrapper class 라고 할 수 있겠다. 308 | 309 | ### 27.2.2. The Array Type 310 | ```cpp 311 | template > 312 | class Array 313 | { 314 | private: 315 | Data data_; 316 | 317 | public: 318 | /* ---------------------------------------------------------- 319 | CONSTRUCTORS 320 | ---------------------------------------------------------- */ 321 | explicit Array(size_t s) 322 | : data_(s) 323 | { 324 | }; 325 | 326 | Array(const Data &obj) 327 | : data_(obj) 328 | { 329 | }; 330 | 331 | Array& operator=(const Array &obj) 332 | { 333 | assert(size() == obj.size()); 334 | for (size_t i = 0; i < size(); ++i) 335 | data_[i] = obj[i]; 336 | return *this; 337 | }; 338 | 339 | /* ---------------------------------------------------------- 340 | ACCESSORS 341 | ---------------------------------------------------------- */ 342 | size_t size() const 343 | { 344 | return data_.size(); 345 | }; 346 | 347 | Data& data() 348 | { 349 | return data_; 350 | }; 351 | const Data& data() const 352 | { 353 | return data_; 354 | }; 355 | 356 | inline T& operator[](size_t index) 357 | { 358 | assert(index < size()); 359 | return data_[index]; 360 | }; 361 | inline const T& operator[](size_t index) const 362 | { 363 | assert(index < size()); 364 | return data_[index]; 365 | }; 366 | }; 367 | ``` 368 | 369 | 그리고 앞서 구현했던 `S_Operator` 를 활용하기 위해, 그리고 `SArray` 와의 차별화를 위해 새로운 Numeric Array 클래스, `Array` 를 새로이 만들었다. 370 | 371 | ### 27.2.3. The Operators 372 | ```cpp 373 | template 374 | auto operator+(const Array &x, const Array &y) -> Array> 375 | { 376 | return Array> 377 | ( 378 | A_Add(x.data(), y.data()) 379 | ); 380 | } 381 | 382 | template 383 | auto operator*(const Array &x, const Array &y) -> Array> 384 | { 385 | return Array> 386 | ( 387 | A_Mult(x.data(), y.data()) 388 | ); 389 | } 390 | 391 | template 392 | auto operator*(T x, const Array &y) -> Array, D2>> 393 | { 394 | auto op = A_Mult, D2>(A_Scalar(x), y.data()); 395 | return Array, D2>>(op); 396 | } 397 | ``` 398 | 399 | 마지막으로 `Array` 와 400 | 401 | ### 27.2.4. Review 402 | [Source](src/expression) 403 | 404 | 구태여 `Array` 클래스를 새로이 만들어야 했던 이유가 있을까? `Array` 가 Numeric Array 에 대한 `Wrapper Class` 역할을 해 주던 것은 이해하나, 구태여 이러한 방식을 고집할 필요는 없어 보인다. `std::vector` 나 `std::deque` 와 같은 일반적인 STL 배열 클래스를 사용해도 위 `operators` 는 얼마든 지 구현할 수 있다. 405 | 406 | ```cpp 407 | template 408 | auto operator+(const Left &x, const Right &y) -> Ret 409 | { 410 | using T = typename Left::value_type; 411 | return Ret(A_Add(x.data(), y.data())); 412 | } 413 | ``` 414 | 415 | 또한, `A_Operator` 에서는 계산에 사용되는 두 변수 (x, y) 의 타입이 모두 `T` 로 고정되어 있으나, 이 또한, 두 변수 (x, y) 가 각기 서로 다른 타입을 갖도록 할 수 있다. 416 | 417 | ```cpp 418 | // 타입 T 가 꼭 필요한 게 아니다. 419 | template 420 | class A_Operator 421 | { 422 | public: 423 | typename A_Traits::Reference x_; 424 | typename A_Traits::Reference y_; 425 | 426 | public: 427 | A_Operator(const X &x, const Y &y) 428 | : x_(x), y_(y) 429 | { 430 | }; 431 | 432 | auto operator[](size_t index) const 433 | { 434 | return Operator()(x_[index], y_[index]); 435 | }; 436 | 437 | size_t size() const 438 | { 439 | // SIZE 0 FOR SCALAR 440 | assert(x_.size() == 0 || y_.size() == 0 || x_.size() == y_.size()); 441 | return x_.size() != 0 442 | ? x_.size() 443 | : y_.size(); 444 | }; 445 | }; 446 | ``` 447 | 448 | 449 | 450 | ## 27.3. Performance and Limitations of Expression Templates 451 | 책을 읽어보자 -------------------------------------------------------------------------------- /1st Study/seminar.md: -------------------------------------------------------------------------------- 1 | # Templates Study 2 | ## 1. The Basics 3 | ### 1.1. Macro & Template 4 | 템플릿이라는 개념은 매크로를 통해 우연히 발견되었다고 한다. 5 | 6 | 옛날옛적, 템플릿이 없던 시절의 개발자들은 매크로를 이용해 Generic 한 매크로 함수를 만들어 썼다. 또한 컬렉션 클래스를 만듦에 있어, 중복 코드를 생성치 않기 위하여 매크로를 이용해 Generic 한 클래스들을 만들어 쓰기도 하였다. 이 시절의 매크로 함수와 클래스가 확장되어 만들어진 것이 지금의 템플릿이다. 7 | 8 | 템플릿의 가장 중요한 특성 중 하나가 바로 compile-time 아닌가? 왜 run-time 이 아닌 compile-time 일까? 매크로의 특성을 생각해보면 뻔하지 않나? 때문에 템플릿을 배울 때, "템플릿은 매크로의 확장판이다" 라는 개념만 기억하고 있으면, 생각보다 템플릿을 쉽고 수월하게 배울 수 있다. 9 | 10 | ```cpp 11 | #define MIN(x, y) (((a)<(b))?(a):(b)) 12 | #define MAX(x, y) (((a)>(b))?(a):(b)) 13 | 14 | #define collection(T) \ 15 | class collection_##T \ 16 | { \ 17 | private: \ 18 | T *data_; \ 19 | size_t size_; \ 20 | size_t capacity_; \ 21 | \ 22 | public: \ 23 | collection_##T() \ 24 | : data_(nullptr), \ 25 | size_(0), capacity_(0) {}; \ 26 | collection_##T(size_t n, const T &val) \ 27 | { \ 28 | data_ = new T[n]; \ 29 | size_ = capacity_ = n; \ 30 | \ 31 | while (n != 0) \ 32 | { \ 33 | *data_++ = val; \ 34 | --n; \ 35 | } \ 36 | }; \ 37 | \ 38 | T* begin() \ 39 | { \ 40 | return data_; \ 41 | }; \ 42 | T* end() \ 43 | { \ 44 | return data_ + size_; \ 45 | }; \ 46 | }; 47 | ``` 48 | 49 | ### 1.2. STL 50 | Standard Template Library. 51 | 52 | C++ Templates 를 대표하는 라이브러리. 아래와 같이 크게 네 파트로 분류됨. 53 | - containers 54 | - iterators 55 | - algorithms 56 | - functors 57 | 58 | STL 이 제공하는 객체들을 둘러보니, 온갖 종류의 Template Features 들이 다채롭게 쓰였떠라. 그렇다면 STL 을 직접 구현해보면 템플릿 도사가 되어있지 않을까? 59 | 60 | ```cpp 61 | namespace mystl 62 | { 63 | template 64 | class tuple; 65 | 66 | template 67 | class tuple 68 | { 69 | private: 70 | Head head_; 71 | 72 | public: 73 | tuple() {}; 74 | tuple(const Head &head) 75 | : head_(head) {}; 76 | 77 | auto _Get_head() const -> const Head& 78 | { 79 | return head_; 80 | }; 81 | }; 82 | 83 | template 84 | class tuple : public tuple 85 | { 86 | private: 87 | tuple tail_; 88 | 89 | public: 90 | tuple() : tuple() {}; 91 | tuple(const Head &head, const tuple &tail) 92 | : tuple(head), tail_(tail) {}; 93 | 94 | auto _Get_tail() const -> const tuple& 95 | { 96 | return tail_; 97 | }; 98 | }; 99 | 100 | template 101 | struct _Tuple_getter 102 | { 103 | template 104 | static auto apply(const Tuple &t) 105 | { 106 | return _Tuple_getter::apply(t._Get_tail()); 107 | }; 108 | }; 109 | 110 | template <> 111 | struct _Tuple_getter<0> 112 | { 113 | template 114 | static auto apply(const Tuple &t) 115 | { 116 | return t._Get_head(); 117 | }; 118 | }; 119 | 120 | template 121 | auto get(const Tuple &t) 122 | { 123 | return _Tuple_getter::apply(t); 124 | }; 125 | }; 126 | ``` 127 | 128 | ### 1.3. Template vs. Generic 129 | Template 은 Macro 를 확장한 것이다. 130 | - Macro 에서 진화한 코드 복제 도구. 131 | - 새로운 타입을 사용할 때마다, 새로운 코드가 생성됨. 132 | - 다른 타입의 템플릿 클래스는, 이름만 비슷할 뿐 아주 다른 클래스임. 133 | > ```cpp 134 | > vector v1; 135 | > vector v2; 136 | > 137 | > bool is_same = typeid(v1) == typeid(v2); 138 | > cout << is_same << endl; // false 139 | > ``` 140 | 141 | Generic 은 자동 타입 변환 도구이다. 142 | - 형 변환을 자동으로 해주는 편의 도구. 143 | - 새로운 타입을 사용해도, 동일한 코드를 사용함. 144 | - 다른 타입의 제네릭 클래스는, 실제 같은 타입의 클래스임. 145 | > ```typescript 146 | > let v1: std.Vector = new std.Vector(); 147 | > let v2: std.Vector = new std.Vector(); 148 | > 149 | > let is_same: boolean = typeof v1 == typeof v2; 150 | > console.log(is_same); // true 151 | > ``` 152 | 153 | Type | Pros | Cons 154 | ---------|--------------------|-------------------------- 155 | Template | 속도가 빠르며, 유연함. | 프로그램의 크기가 커진다. 156 | Generic | 프로그램의 크기가 작다. | 속도가 느리며, 유연하지 못하다. 157 | 158 | ```cpp 159 | namespace std 160 | { 161 | template, 163 | typename Pred = equal_to, 164 | typename Alloc = allocator> 165 | > class unordered_map 166 | { 167 | public: 168 | template 169 | void assign(InputIterator first, InputIterator last); 170 | }; 171 | }; 172 | ``` 173 | 174 | ```ts 175 | namespace std 176 | { 177 | class HashMap 178 | { 179 | public constructor 180 | ( 181 | hash_fn: (key: Key) => number = std.hash, 182 | equal_fn: (x: Key, y: Key) => boolean = std.equal_to 183 | ); 184 | 185 | public assign>> 186 | (first: IForwardIterator, last: IForwardIterator): void; 187 | } 188 | 189 | interface IForwardIterator 190 | { 191 | readonly value: T; 192 | next(): IForwardIterator; 193 | equals(obj: IForwardIterator): boolean; 194 | } 195 | 196 | interface IPair 197 | { 198 | first: First; 199 | second: Second; 200 | } 201 | class Entry implements IPair, IComparable> 202 | { 203 | public readonly first: Key; 204 | public second: T; 205 | 206 | public less(obj: Entry): boolean; 207 | public equals(obj: Entry): boolean; 208 | public hashCode(): number; 209 | } 210 | } 211 | ``` 212 | 213 | 214 | ## 2. Function Templates 215 | ### 2.1. Template Parameters 216 | ```cpp 217 | template 218 | T max(T x, T y) 219 | { 220 | return x > y ? x : y; 221 | } 222 | ``` 223 | 224 | ### 2.2. Argument Deduction 225 | ```cpp 226 | template 227 | X max(X x, Y y) 228 | { 229 | return x > y ? x : y; 230 | }; 231 | 232 | template 233 | Ret max(X x, Y y) 234 | { 235 | return x > y ? x : y; 236 | }; 237 | ``` 238 | 239 | ```cpp 240 | template 241 | auto max(X x, Y y); 242 | 243 | template 244 | auto max(X x, Y y) -> decltype(a > b ? a : b); 245 | 246 | template 247 | auto max(X x, Y y) -> std::decay b ? a : b)>::type; 248 | 249 | template 250 | auto max(X x, Y y) -> std::common_type_t; 251 | 252 | template b ? a : b)>::type> 254 | auto max(X x, Y y) -> Ret; 255 | ``` 256 | 257 | ```cpp 258 | std::decay::type; // int 259 | std::decay::type; // int 260 | std::decay::type; // int 261 | std::decay::type; // int 262 | std::decay::type; // int 263 | std::decay::type; // int 264 | ``` 265 | 266 | ### 2.3. Overloading Function Templates 267 | ```cpp 268 | template<> 269 | short max(short x, short y) 270 | { 271 | return (x + (~y + 1) >> 15 == 0) ? x : y; 272 | }; 273 | 274 | template<> 275 | int max(int x, int y) 276 | { 277 | return (x + (~y + 1) >> 31 == 0) ? x : y; 278 | }; 279 | 280 | template 281 | auto max(X x, Y y, Z z) 282 | { 283 | return max(x, max(y, z)); 284 | }; 285 | ``` 286 | 287 | ```cpp 288 | namespace mystl 289 | { 290 | template 291 | std::string to_string(T); 292 | 293 | template<> std::string to_string(short val); 294 | template<> std::string to_string(int val); 295 | template<> std::string to_string(double val); 296 | }; 297 | ``` 298 | 299 | 300 | 301 | ## 3. Class Templates 302 | ### 3.1. Implementation 303 | 클래스에 Template Argument 를 사용, 클래스 내 멤버에 Generic 한 타입을 사용할 수 있다. 304 | - Variables 305 | - Methods 306 | - Type Definitions 307 | 308 | 클래스 템플릿의 가장 대표적인 사례는 Container 이다. STL Containers 의 선언부를 살펴보자. 309 | 310 | ```cpp 311 | namespace std 312 | { 313 | //---- 314 | // LINEAR CONTAINERS 315 | //---- 316 | template > 317 | class vector; 318 | 319 | template > 320 | class vector; // OVERLOADED TEMPLATE CLASS 321 | 322 | template > 323 | class list; 324 | 325 | //---- 326 | // ASSOCIATIVE CONTAINERS 327 | //---- 328 | template 329 | < 330 | typename Key, 331 | typename T, 332 | typename Comp = less, 333 | typename Alloc = allocator> 334 | > class map; // TREE-MAP 335 | 336 | template 337 | < 338 | typename Key, 339 | typename T, 340 | typename Hash = hash, 341 | typename Pred = equal_to, 342 | typename Alloc = allocator> 343 | > class unordered_map; // HASH-MAP 344 | }; 345 | ``` 346 | 347 | ```cpp 348 | namespace mystl 349 | { 350 | template 351 | class stack 352 | { 353 | private: 354 | std::vector elems_; 355 | 356 | public: 357 | bool empty() const 358 | { 359 | return elems_.empty(); 360 | }; 361 | const T& top() const 362 | { 363 | return elems_.back(); 364 | }; 365 | 366 | void push(const T &elem) 367 | { 368 | elems_.push_back(elem); 369 | }; 370 | void pop() 371 | { 372 | elems_.pop_back(); 373 | }; 374 | }; 375 | }; 376 | ``` 377 | 378 | ### 3.2. Speciailizations 379 | ```cpp 380 | namespace mystl 381 | { 382 | template <> 383 | class stack 384 | { 385 | private: 386 | std::deque elems_; 387 | 388 | public: 389 | bool empty() const; 390 | const std::string& top() const; 391 | 392 | void push(const std::string &elem); 393 | void pop(); 394 | }; 395 | } 396 | ``` 397 | 398 | ```cpp 399 | namespace std 400 | { 401 | template > 402 | class deque 403 | { 404 | private: 405 | vector> data_; 406 | size_t size_; 407 | size_t capacity_; 408 | 409 | public: 410 | void pop_front(); 411 | void push_front(const T &elem); 412 | }; 413 | }; 414 | ``` 415 | 416 | ```cpp 417 | namespace std 418 | { 419 | // BOOL SPECIALIZATION 420 | template > 421 | class vector; 422 | }; 423 | ``` 424 | 425 | ### 3.3. Utilities 426 | #### 3.3.1. Default Argument 427 | ```cpp 428 | namespace mystl 429 | { 430 | template > 431 | class stack 432 | { 433 | private: 434 | Container elems_; 435 | 436 | public: 437 | bool empty() const; 438 | const T& top() const; 439 | 440 | void push(const T &elem); 441 | void pop(); 442 | }; 443 | }; 444 | ``` 445 | 446 | #### 3.3.2. Overloadings 447 | ```cpp 448 | namespace mystl 449 | { 450 | template 451 | class tuple; 452 | 453 | template 454 | class tuple 455 | { 456 | private: 457 | Head head_; 458 | 459 | public: 460 | tuple() {}; 461 | tuple(const Head &head) 462 | : head_(head) {}; 463 | 464 | auto _Get_head() const -> const Head& 465 | { 466 | return head_; 467 | }; 468 | }; 469 | 470 | template 471 | class tuple : public tuple 472 | { 473 | private: 474 | tuple tail_; 475 | 476 | public: 477 | tuple() : tuple() {}; 478 | tuple(const Head &head, const tuple &tail) 479 | : tuple(head), tail_(tail) {}; 480 | 481 | auto _Get_tail() const -> const tuple& 482 | { 483 | return tail_; 484 | }; 485 | }; 486 | 487 | template 488 | class _Tuple_getter 489 | { 490 | template 491 | static auto apply(const Tuple &t) 492 | { 493 | return _Tuple_getter::apply(t._Get_tail()); 494 | }; 495 | }; 496 | 497 | template <> 498 | class _Tuple_getter<0> 499 | { 500 | template 501 | static auto apply(const Tuple &t) 502 | { 503 | return t._Get_head(); 504 | }; 505 | }; 506 | 507 | template 508 | auto get(const Tuple &t) 509 | { 510 | return _Tuple_getter::apply(t); 511 | }; 512 | }; 513 | ``` -------------------------------------------------------------------------------- /7th Study/Chap13.md: -------------------------------------------------------------------------------- 1 | 2 | 18/03/24 진행: [박동하](https://github.com/luncliff) luncliff@gmail.com 3 | 4 | ### 추가 자료 5 | - [Templates and Name Resolution](https://docs.microsoft.com/en-us/cpp/cpp/templates-and-name-resolution) 6 | - [Name Resolution for Locally Declared Names](https://docs.microsoft.com/en-us/cpp/cpp/name-resolution-for-locally-declared-names) 7 | - [Function Overloading](https://docs.microsoft.com/en-us/cpp/cpp/function-overloading) 8 | - [Overload Resolution for Template Calls](https://docs.microsoft.com/en-us/cpp/cpp/overload-resolution-of-function-template-calls) 9 | 10 | 11 | # Chapter 13: 템플릿과 이름 12 | > Names in Templates 13 | 14 | - 이름은 프로그래머가 부여하는 것 15 | - C++ 컴파일러는 이름을 발견하면, 어떤 존재(entity)를 가리키는 것인지 "탐색"해야함 16 | (C++ 언어를 구현하는 입장에선 굉장히 어려운 일) 17 | 18 | C++은 문맥 인식(context sensitive) 언어: 19 | - 하나를 이해하기 위해선 더 넓은 문맥(context)를 알아야만 한다는 의미 20 | 21 | ``` 22 | x * y; // x가 변수인 경우 - 곱셈(아마도) 23 | // x가 타입인 경우 - x 포인터 변수 y의 선언 24 | ``` 25 | 26 | 템플릿과의 상관성? 27 | 1. 템플릿이 발견된 문맥 28 | 1. 템플릿이 실체화되는 문맥 29 | 1. 실체화되는 템플릿 인자와 관련된 문맥 30 | 31 | ## 1. 이름 분류 32 | > Name Taxonomy 33 | 34 | C++ 에서의 이름에 대한 정리(요약). 필요하면 찾아보는 정도면 충분 35 | 36 | | 분류 | | 37 | |:-----|:-----| 38 | | Identifier | 식별자 39 | | Operator-function-id | `new`, `operator[]` 40 | | Conversion-function-id | `operator int()` 41 | | Literal-operator-id | `100_km` 42 | | Template-id | `List`. 꺾음 괄호 `<>`로 묶인 템플릿 인자가 따라옴(후속) 43 | | Uniqualified-id | 일반적인 식별자. Operator, Conversion, Literal, Destructor 44 | | Qualified-id | 한정된(조건부) 식별자. `class`, `union`, `namespace`등의 이름. Global scope resolution operator(`::`) 포함. 45 | | Qualified name | 한정된(조건부) 이름. Qualified Lookup의 대상. Qualified ID 혹은 명시적인 멤버 접근(`.` 또는 `->`)을 사용하는 Unqualified ID 46 | | Unqualified name | 제약이 걸리지 않은 이름. Unqualified Lookup의 대상 47 | | Dependent name | 템플릿 인자에 (어떤 형태로든) 의존하는 이름 48 | | Nondependent name | 의존적이지 않은 모든 이름 49 | 50 | ## 2. 이름 탐색 51 | > Looking Up Names 52 | 53 | 54 | **Qualified Lookup**: 지정된 조건 하에서의 탐색. 55 | `void f(D* pd)` 함수 내에서 `i`와 `x`는 Qualified Name. 56 | ```c++ 57 | int x; 58 | 59 | class B { 60 | public: 61 | int i; 62 | }; 63 | 64 | class D : public B { 65 | }; 66 | 67 | void f(D* pd) 68 | { 69 | pd->i = 3; // B::i 를 찾아낸다. (상위 클래스는 탐색 범위에 포함됨) 70 | D::x = 2; // ERROR: ::x 가 D 안에 없음 (바깥 Scope는 탐색 범위에 포함하지 않음) 71 | } 72 | ``` 73 | 74 | **Unqualified Lookup**: 한정되지 않은(특별한 제약이 없는) 경우, 계속해서 바깥 Scope를 탐색. 75 | ```c++ 76 | extern int count; // #1 77 | 78 | int lookup_example(int count) // #2 79 | { 80 | if(count < 0){ 81 | int count = 1; // #3 82 | lookup_example(count); // 제약이 없으므로 가장 가까운 #3 선택 83 | } 84 | return count // 가장 가까운 #2 선택 85 | + ::count; // 전역 한정(Qualified). #1 선택 86 | } 87 | ``` 88 | 89 | 앞서까지의 방법은 Ordinary Lookup. 템플릿을 위해 추가된 방법이 ADL. 90 | 91 | ```c++ 92 | template 93 | T max(T a, T b) 94 | { 95 | return b < a ? a : b; 96 | } 97 | 98 | namespace BigMath 99 | { 100 | class BigNum 101 | { 102 | // ... 103 | }; 104 | 105 | bool operator < (BigNum const&, BigNum const&); 106 | // ... 107 | } 108 | 109 | using BigMath::BigNum; 110 | 111 | void g(BigNum const& a, BigNum const& b) 112 | { 113 | // ... 114 | BigNum x = ::max(a, b); 115 | } 116 | ``` 117 | `max()` 템플릿 함수는 BigMath 네임스페이스(이름공간)를 볼 수 었음. 따라서 Ordinary Lookup으로는 `operator <`를 적용 불가. 이것을 가능하게 하는 **특별한 규칙**이 필요. 118 | 119 | ### 2.1 Argument-Dependent Lookup 120 | 121 | 정의: 템플릿 함수를 호출하면(소괄호가 `()` 따라오면), 인자들의 타입과 관련된 네임스페이스/타입에서 탐색을 수행한다 122 | 123 | 조건: Ordinary Lookup이 다음 중 하나라도 찾아내면 일어나지 않음 124 | - 멤버 함수 125 | - 변수 126 | - 타입 127 | - 블록에서의 함수 선언(?) 128 | 129 | | Type | Associated Namespace/Class | 130 | |:-----|:-----| 131 | | Built-In Types | 없음 132 | | Pointer/Array | 기반 타입 T와 해당 타입이 포함된 네임스페이스 133 | | Enum | 선언된 네임스페이스 134 | | Class Member | 멤버가 포함된 클래스 135 | | Class (+ Union) | 클래스 자신(itself), 자신을 내포하는 클래스, 직/간접적 상위 클래스. 이들이 선언된 네임스페이스들 136 | | Function | 모든 인자와 리턴 타입의 연관된 네임스페이스/클래스 137 | | Pointer to Class Member Variable | Class의 연관된 네임스페이스/클래스 138 | | Pointer to Class Member Function | Class와 함수 인자/리턴 타입들의 연관된 네임스페이스/클래스들 139 | 140 | 예제: 141 | ```c++ 142 | #include 143 | 144 | namespace X 145 | { 146 | template 147 | void f(T); 148 | } 149 | 150 | namespace N 151 | { 152 | using namespace X; 153 | 154 | enum E 155 | { 156 | e1 157 | }; 158 | 159 | void f(E){ 160 | std::cout << "N::f(N::E) called" << std::endl; 161 | } 162 | } 163 | 164 | void f(int){ 165 | std::cout << "::f(int) called" << std::endl; 166 | } 167 | 168 | int main() 169 | { 170 | ::f(N::e1); // f는 Qualified name. ADL 적용하지 않음 171 | f(N::e1); // Ordinary --> ::f(int) 172 | // ADL --> N::f(N::E) 173 | // ADL 의 함수가 선택됨 (인자의 적합성) 174 | } 175 | ``` 176 | 177 | ### 2.2 Friend 선언에서의 ADL (생략) 178 | > ADL of Friend Declarations 179 | 180 | ### 2.3 클래스 이름 주입 181 | > Injected Class Name 182 | 183 | **이름 주입**: 클래스를 선언하는 경우, **선언하는 도중에도** 클래스 이름에 접근이 가능. 단, Unqualified Name이어야 함 184 | 185 | ```c++ 186 | #include 187 | 188 | int C; 189 | 190 | class C 191 | { 192 | private: 193 | int i[2]; 194 | 195 | public: 196 | static int f() { 197 | // Name injection: Size of this type 198 | return sizeof(C); 199 | } 200 | }; 201 | 202 | int f() 203 | { 204 | // size of the variable 205 | return sizeof(C); 206 | } 207 | ``` 208 | 209 | - 템플릿에 대해서도 마찬가지로 적용 210 | - +) 템플릿 인자가 따라올 수 있음 211 | 212 | ```c++ 213 | template