Last active
March 16, 2022 09:33
-
-
Save dboyliao/95f827d584df1c8b66cb8d0fe55b6725 to your computer and use it in GitHub Desktop.
Revisions
-
dboyliao revised this gist
Mar 16, 2022 . 1 changed file with 5 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -4,4 +4,8 @@ $ mkdir -p build $ cmake -B build -S . $ cmake --build build ``` # References - https://stackoverflow.com/questions/149336/practical-uses-for-the-curiously-recurring-template-pattern -
dboyliao revised this gist
Mar 16, 2022 . 2 changed files with 7 additions and 8 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -3,6 +3,6 @@ #include "public.hpp" float CartesianPoint::dist() const { return std::hypot(v0(), v1()); } float PolarPoint::dist() const { return std::abs(v0()); } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -12,12 +12,13 @@ class PointBase { float const &v1() const { return m_v1; } float &v1() { return m_v1; } float dist() const { static_assert(&Derived::dist != &PointBase::dist, "derived class must overwrite dist"); auto &obj = derived(); return obj.dist(); } private: Derived const &derived() const { return *static_cast<Derived const *>(this); } float m_v0, m_v1; @@ -37,7 +38,7 @@ class CartesianPoint : public PointBase<CartesianPoint> { using PointBase<CartesianPoint>::PointBase; private: float dist() const; friend class PointBase<CartesianPoint>; }; @@ -46,7 +47,7 @@ class PolarPoint : public PointBase<PolarPoint> { using PointBase<PolarPoint>::PointBase; private: float dist() const; friend class PointBase<PolarPoint>; }; @@ -55,7 +56,6 @@ class BadPoint : public PointBase<BadPoint> { using PointBase<BadPoint>::PointBase; private: friend class PointBase<BadPoint>; }; @@ -64,6 +64,5 @@ class BadBadPoint : public PointBase<BadPoint> { using PointBase<BadPoint>::PointBase; private: friend class PointBase<BadPoint>; }; -
dboyliao revised this gist
Mar 16, 2022 . 2 changed files with 1 addition and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,3 +1,4 @@ build lib bin .vscode This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,5 +1,3 @@ #include <cstdint> #include <utility> -
dboyliao revised this gist
Mar 16, 2022 . 2 changed files with 9 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -3,9 +3,9 @@ project(crtp_example LANGUAGES CXX) set(CMAKE_CXX_STANDARD 11) set(CMAKE_VERBOSE_MAKEFILE ON) add_library(public_lib SHARED private.cpp) target_include_directories(public_lib PUBLIC ${CMAKE_SOURCE_DIR} ) set_target_properties(public_lib PROPERTIES This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,7 @@ # Build ```bash $ mkdir -p build $ cmake -B build -S . $ cmake --build build ``` -
dboyliao revised this gist
Mar 16, 2022 . 2 changed files with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes.File renamed without changes. -
dboyliao revised this gist
Mar 16, 2022 . 5 changed files with 103 additions and 64 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,3 @@ build lib bin This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,20 @@ cmake_minimum_required(VERSION 3.8) project(crtp_example LANGUAGES CXX) set(CMAKE_CXX_STANDARD 11) set(CMAKE_VERBOSE_MAKEFILE ON) add_library(public_lib SHARED src/private.cpp) target_include_directories(public_lib PUBLIC include ) set_target_properties(public_lib PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib ) add_executable(${PROJECT_NAME} ${CMAKE_SOURCE_DIR}/crtp.cpp) target_link_libraries(${PROJECT_NAME} public_lib) set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin ) This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,70 +1,9 @@ #include <cstdint> #include <utility> #include "public.hpp" int main(int, char **) { std::cout << "sizeof(CartesianPoint) = " << sizeof(CartesianPoint) This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,69 @@ #include <iostream> template <class Derived> class PointBase { public: constexpr static const double PI = 3.14159265358979323846; PointBase(float v0, float v1) : m_v0(v0), m_v1(v1) { std::cout << "PointBase: " << this << std::endl; } float const &v0() const { return m_v0; } float &v0() { return m_v0; } float const &v1() const { return m_v1; } float &v1() { return m_v1; } float dist() const { auto &obj = derived(); return obj.dist_impl(); } private: virtual float dist_impl() const = 0; Derived const &derived() const { return *static_cast<Derived const *>(this); } float m_v0, m_v1; private: // safe guard for invalid inheritance PointBase() {} friend Derived; }; /* end class PointBase */ template <typename Derived> float use_dist(const PointBase<Derived> &pt) { return pt.dist(); } class CartesianPoint : public PointBase<CartesianPoint> { public: using PointBase<CartesianPoint>::PointBase; private: float dist_impl() const; friend class PointBase<CartesianPoint>; }; class PolarPoint : public PointBase<PolarPoint> { public: using PointBase<PolarPoint>::PointBase; private: float dist_impl() const; friend class PointBase<PolarPoint>; }; class BadPoint : public PointBase<BadPoint> { public: using PointBase<BadPoint>::PointBase; private: float dist_impl() const { return -1.0; } friend class PointBase<BadPoint>; }; class BadBadPoint : public PointBase<BadPoint> { public: using PointBase<BadPoint>::PointBase; private: float dist_impl() const { return -1.0; } friend class PointBase<BadPoint>; }; This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,8 @@ #include <algorithm> #include <cmath> #include "public.hpp" float CartesianPoint::dist_impl() const { return std::hypot(v0(), v1()); } float PolarPoint::dist_impl() const { return std::abs(v0()); } -
dboyliao created this gist
Mar 16, 2022 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,90 @@ #include <algorithm> #include <cmath> #include <cstdint> #include <iostream> #include <utility> template <class Derived> class PointBase { public: constexpr static const double PI = 3.14159265358979323846; PointBase(float v0, float v1) : m_v0(v0), m_v1(v1) { std::cout << "PointBase: " << this << std::endl; } float const &v0() const { return m_v0; } float &v0() { return m_v0; } float const &v1() const { return m_v1; } float &v1() { return m_v1; } float dist() const { // Prevent the derived class from working if it doesn't define dist(), // just like what a pure virtual function does. static_assert(&PointBase<Derived>::dist != &Derived::dist, "derived class must define dist()"); return static_cast<const Derived *>(this)->dist(); } private: Derived const &derived() const { return *static_cast<Derived const *>(this); } float m_v0, m_v1; private: // safe guard for invalid inheritance PointBase() {} friend Derived; }; /* end class PointBase */ template <typename Derived> float use_dist(const PointBase<Derived> &pt) { return pt.dist(); } class CartesianPoint : public PointBase<CartesianPoint> { public: using PointBase<CartesianPoint>::PointBase; float dist() const { return std::hypot(v0(), v1()); } }; /* end class CartesianPoint */ class PolarPoint : public PointBase<PolarPoint> { public: using PointBase<PolarPoint>::PointBase; float dist() const { return std::abs(v0()); } }; /* end class PolarPoint */ class BadPoint : public PointBase<BadPoint> { public: using PointBase<BadPoint>::PointBase; // Intentionally omit dist(). /*float dist() const { return 0.0; }*/ }; /* end class BadPoint */ // intentionally iheritant from wrong base class class BadBadPoint : public PointBase<BadPoint> { public: using PointBase<BadPoint>::PointBase; }; int main(int, char **) { std::cout << "sizeof(CartesianPoint) = " << sizeof(CartesianPoint) << std::endl; std::cout << "sizeof(PolarPoint) = " << sizeof(PolarPoint) << std::endl; CartesianPoint cpt(1, 1); PolarPoint ppt(1, PolarPoint::PI / 4); std::cout << "CartesianPoint(1,1)::dist() = " << use_dist(cpt) << std::endl; std::cout << "PolarPoint(1, pi/4)::dist() = " << use_dist(ppt) << std::endl; // This won't compile // error: static_assert failed "derived class must define dist()" // BadPoint bp; // use_dist(bp); // This won't compile // since the default constructor is not accessible to BadBadPoint (due to // incorrect usage of CRTP) // BadBadPoint bbp; return 0; }