diff --git a/CMakeLists.txt b/CMakeLists.txt index fc42457..ae3536f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,8 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(BOOST_INCLUDE_LIBRARIES "pfr") +set(NAMEOF_OPT_INSTALL ON) + option(CPM_USE_LOCAL_PACKAGES "Use local packages" ON) option(UTEMPL_MODULE OFF) @@ -49,22 +51,24 @@ set(TMP ${CPM_USE_LOCAL_PACKAGES}) set(CPM_USE_LOCAL_PACKAGES OFF) CPMAddPackage( - NAME fmt + NAME nameof URL - "https://github.com/fmtlib/fmt/releases/download/11.0.2/fmt-11.0.2.zip" + "https://helicopter.myftp.org/git/sha512sum/nameof_module/archive/master.tar.gz" EXCLUDE_FROM_ALL ON - OPTIONS "FMT_MODULE ON" + OPTIONS "NAMEOF_MODULE ON" ) set(CPM_USE_LOCAL_PACKAGES ${TMP}) else() -CPMAddPackage("gh:fmtlib/fmt#11.0.2") +CPMAddPackage("gh:Neargye/nameof@0.10.4") endif() + + cmake_policy(SET CMP0079 NEW) include(GNUInstallDirs) @@ -106,11 +110,11 @@ if(UTEMPL_MODULE) endif() endforeach() if(TARGET Boost::pfr) - target_link_libraries(utempl PUBLIC fmt::fmt + target_link_libraries(utempl PUBLIC nameof::nameof Boost::pfr) else() find_package(Boost 1.85.0 REQUIRED) - target_link_libraries(utempl PUBLIC fmt::fmt + target_link_libraries(utempl PUBLIC nameof::nameof ${Boost_LIBRARIES}) endif() target_include_directories(utempl PUBLIC @@ -146,12 +150,12 @@ else() endif() endforeach() if(TARGET Boost::pfr) - target_link_libraries(utempl INTERFACE fmt::fmt - Boost::pfr) + target_link_libraries(utempl INTERFACE nameof::nameof + Boost::pfr nameof::nameof) else() find_package(Boost 1.85.0 REQUIRED) - target_link_libraries(utempl INTERFACE fmt::fmt - ${Boost_LIBRARIES}) + target_link_libraries(utempl INTERFACE nameof::nameof + ${Boost_LIBRARIES} nameof::nameof) endif() target_include_directories(utempl INTERFACE $ diff --git a/examples/src/public_cast.cpp b/examples/src/public_cast.cpp new file mode 100644 index 0000000..3849bd0 --- /dev/null +++ b/examples/src/public_cast.cpp @@ -0,0 +1,38 @@ +#include + +using namespace utempl; // NOLINT + +struct A { + private: + [[nodiscard]] constexpr auto Method() const -> int { + return 1; + }; + [[nodiscard]] constexpr auto Method(int) const -> int { + return 2; + }; + [[nodiscard]] constexpr auto Method() -> int { + return 3; + }; +}; + +namespace utempl { + +template struct PublicCast(&A::Method)>; + +template struct PublicCast(&A::Method)>; + +template struct PublicCast(&A::Method)>; + +} // namespace utempl + +constexpr A a; + +static_assert(GetPrivateMemberOverloaded<"Method">(a) == 1); +static_assert(GetPrivateMemberOverloaded<"Method">(a, 1) == 2); +static_assert(GetPrivateMemberOverloaded<"Method">(A{}) == 3); + +static_assert((a.*GetPrivateMember<"Method", 0, A>())() == 1); + +static_assert((a.*GetPrivateMember<"Method", 1>(a))(1) == 2); + +auto main() -> int {}; diff --git a/src/public_cast.cpp b/src/public_cast.cpp new file mode 100644 index 0000000..94490a1 --- /dev/null +++ b/src/public_cast.cpp @@ -0,0 +1,80 @@ +#pragma once + +#include + +#ifdef UTEMPL_MODULE + +export module utempl.public_cast; +import utempl.loopholes; +import std; +import utempl.overloaded; +import utempl.string; +import nameof; + +#else +#include +#include +#include +#endif + +namespace utempl { + +namespace impl { // For headers + +template +struct PublicCast { + template + struct Tag {}; +}; + +template +using MainT = decltype(Overloaded([](R (T::*ptr)(Args...)) -> T {}, + [](R (T::*ptr)(Args...) const) -> T {}, + [](R T::* ptr) -> T {})(std::declval())); + +template +constexpr auto TransformPtr() { + return utempl::Overloaded( + [](R (T::*)(Args...)) { + return [](T* obj, Args... args) -> R { + return (obj->*ptr)(std::forward(args)...); + }; + }, + [](R (T::*)(Args...) const) { + return [](const T* obj, Args... args) -> R { + return (obj->*ptr)(std::forward(args)...); + }; + })(ptr); +}; + +} // namespace impl + +UTEMPL_EXPORT template , + ConstexprString Str = + utempl::ConstexprString().size() + 1>{nameof::nameof_member()}, + typename Tag = impl::PublicCast, + auto I = loopholes::Counter(), + auto = loopholes::Injector{}, Ptr>{}> +struct PublicCast {}; + +UTEMPL_EXPORT template +constexpr auto GetPrivateMember() -> decltype(Magic(loopholes::Getter::template Tag{}>{})) { + return Magic(loopholes::Getter::template Tag{}>{}); +} + +UTEMPL_EXPORT template +constexpr auto GetPrivateMember(const T&) -> decltype(GetPrivateMember>()) { + return GetPrivateMember>(); +} + +UTEMPL_EXPORT template +constexpr auto GetPrivateMemberOverloaded(T&& obj, Args&&... args) -> decltype(auto) { + return [&](std::index_sequence) -> decltype(auto) { + return Overloaded(impl::TransformPtr>()>()...)(std::addressof(obj), + std::forward(args)...); + }(std::make_index_sequence, Name>, decltype(F)>()>()); +}; + +} // namespace utempl diff --git a/src/utempl_module.cpp b/src/utempl_module.cpp index ec4dc9f..757cc18 100644 --- a/src/utempl_module.cpp +++ b/src/utempl_module.cpp @@ -13,6 +13,7 @@ export import utempl.overloaded; export import utempl.utils; export import utempl.go_interface; export import utempl.optional; +export import utempl.public_cast; #else #include @@ -23,6 +24,7 @@ export import utempl.optional; #include #include #include +#include #include #include diff --git a/src/utils.cpp b/src/utils.cpp index 4c9efae..b15aa81 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -5,7 +5,6 @@ #ifdef UTEMPL_MODULE export module utempl.utils; import std; -import fmt; import utempl.string; import utempl.tuple; import utempl.type_list;