Skip to content

Commit

Permalink
Add: TypeCast
Browse files Browse the repository at this point in the history
  • Loading branch information
huanmie committed Aug 5, 2022
1 parent 11441b4 commit 5d1abc3
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 0 deletions.
13 changes: 13 additions & 0 deletions TypeCast/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 3.15)

project(TypeCast)
add_library(${PROJECT_NAME} INTERFACE)
target_include_directories(${PROJECT_NAME} INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
install(FILES TypeCast.h DESTINATION include)

project(Example)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(${PROJECT_NAME} TypeCast.cpp)
target_include_directories(${PROJECT_NAME} PRIVATE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> $<INSTALL_INTERFACE:include>)
target_link_libraries(${PROJECT_NAME} PRIVATE TypeCast)
31 changes: 31 additions & 0 deletions TypeCast/TypeCast.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <variant>
#include <iostream>
#include <type_traits>
#include "TypeCast.h"

struct Base { virtual ~Base() {} };
struct Derived1 :Base {};
struct Derived2 :Base {};
struct Derived3 :Derived1 {};
struct Derived4 :Derived3 {};

struct Dispatcher
{
void operator()(Derived1*) { std::cout << "Derived1\n"; }
void operator()(Derived2*) { std::cout << "Derived2\n"; }
void operator()(Derived3*) { std::cout << "Derived3\n"; }
void operator()(Derived4*) { std::cout << "Derived4\n"; }
template<typename T>
void operator()(T*) { std::cout << "Not found\n"; }
};

int main()
{
Base base;
Derived4 derived4;
std::visit(Dispatcher{}, TypeCast::InstanceOf<Derived1*, Derived2*, Derived3*, Derived4*>((Base*)&derived4));
std::visit(Dispatcher{}, TypeCast::InstanceOf<Derived4*, Derived3*, Derived2*, Derived1*>((Base*)&derived4));
std::visit(Dispatcher{}, TypeCast::InstanceOf<Derived1*, Derived2*, Derived3*, Derived4*>(&base));
std::visit(Dispatcher{}, TypeCast::InstanceOf<>((Base*)&derived4));
return 0;
}
29 changes: 29 additions & 0 deletions TypeCast/TypeCast.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once

namespace TypeCast
{
namespace Detail
{
template<typename Ret, typename This>
void InstanceOf(Ret&& result, This&& value) {}

template<typename First, typename... Rest, typename Ret, typename This>
void InstanceOf(Ret&& result, This&& value)
{
auto pointer = dynamic_cast<First>(value);
if (pointer)
result.emplace<First>(pointer);
else
InstanceOf<Rest...>(result, value);
}
}

template<typename... Rest, typename This>
requires std::is_pointer_v<This> && (std::is_pointer_v<Rest>&&...)
std::variant<This, Rest...> InstanceOf(This&& value)
{
std::variant<This, Rest...> result(value);
Detail::InstanceOf<Rest...>(result, value);
return result;
}
}

0 comments on commit 5d1abc3

Please sign in to comment.