Last active
November 12, 2020 02:40
-
-
Save cataphract/e34b3a3bc63d8e89cfd3476c81d24219 to your computer and use it in GitHub Desktop.
This file contains 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 characters
#include <iostream> | |
#include <type_traits> | |
struct type_to_convert { | |
type_to_convert(int i) : i(i) {}; | |
type_to_convert(const type_to_convert&) = delete; | |
type_to_convert(type_to_convert&&) = delete; | |
int i; | |
}; | |
struct X { | |
X(int i) : i(i) {}; | |
X(const X &) = delete; | |
X(X &&) = delete; | |
public: | |
int i; | |
}; | |
struct Y : X { | |
Y(int i) : X{i + 1} {} | |
}; | |
struct A {}; | |
template<typename> | |
static auto convert(const type_to_convert &t, int *) { | |
return t.i; | |
} | |
template<typename U> | |
static auto convert(const type_to_convert &t, X *) { | |
return U{t.i}; // will instantiate either X or a subtype | |
} | |
template<typename> | |
static auto convert(const type_to_convert &t, A *) { | |
return 42; | |
} | |
template<typename T /* requested type, though not necessarily gotten */> | |
static auto convert(const type_to_convert &t) { | |
return convert<T>(t, static_cast<T*>(nullptr)); | |
} | |
int main() { | |
std::cout << convert<int>(type_to_convert{5}) << std::endl; | |
std::cout << convert<X>(type_to_convert{6}).i << std::endl; | |
std::cout << convert<Y>(type_to_convert{6}).i << std::endl; | |
std::cout << convert<A>(type_to_convert{-1}) << std::endl; | |
return 0; | |
} |
This file contains 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 characters
#include <iostream> | |
#include <type_traits> | |
struct type_to_convert { | |
type_to_convert(int i) : i(i) {}; | |
type_to_convert(const type_to_convert&) = delete; | |
type_to_convert(type_to_convert&&) = delete; | |
int i; | |
}; | |
struct X { | |
X(int i) : i(i) {}; | |
X(const X &) = delete; | |
X(X &&) = delete; | |
public: | |
int i; | |
}; | |
struct Y : X { | |
Y(int i) : X{i + 1} {} | |
}; | |
struct A {}; | |
template<typename T /* requested type, though not necessarily gotten */, | |
typename = void> | |
struct convert_t { | |
static auto convert(const type_to_convert &t) { | |
static_assert(!sizeof(T), "no conversion"); | |
} | |
}; | |
template<> | |
struct convert_t<int> { | |
static auto convert(const type_to_convert &t) { | |
return t.i; | |
} | |
}; | |
template<typename T> | |
struct convert_t<T, std::enable_if_t<std::is_base_of_v<X, T>, void>> { | |
static auto convert(const type_to_convert &t) { | |
return T{t.i}; // will instantiate either X or a subtype | |
} | |
}; | |
template<typename T> | |
struct convert_t<T, std::enable_if_t<std::is_base_of_v<A, T>>> { | |
static auto convert(const type_to_convert &t) { | |
return 42; // will instantiate either X or a subtype | |
} | |
}; | |
template<typename T> | |
auto convert(const type_to_convert& t) { | |
return convert_t<T>::convert(t); | |
} | |
int main() { | |
std::cout << convert<int>(type_to_convert{5}) << std::endl; | |
std::cout << convert<X>(type_to_convert{6}).i << std::endl; | |
std::cout << convert<Y>(type_to_convert{6}).i << std::endl; | |
std::cout << convert<A>(type_to_convert{-1}) << std::endl; | |
return 0; | |
} |
This file contains 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 characters
#include <iostream> | |
#include <type_traits> | |
struct type_to_convert { | |
type_to_convert(int i) : i(i) {}; | |
type_to_convert(const type_to_convert&) = delete; | |
type_to_convert(type_to_convert&&) = delete; | |
int i; | |
}; | |
template<typename T /* requested type, though not necessarily gotten */, typename = void> | |
struct convert_t; | |
// specializations | |
template<> | |
struct convert_t<int> { | |
static auto convert(type_to_convert& t) { | |
return t.i; | |
} | |
}; | |
struct X { | |
X(int i) : i(i) {}; | |
X(const X &) = delete; | |
X(X &&) = delete; | |
public: | |
int i; | |
}; | |
struct Y : X { | |
Y(int i) : X{i + 1} {} | |
}; | |
struct A {}; | |
struct class_conversions { | |
template<typename U> | |
static auto convert(type_to_convert& t, X*) { | |
return U{t.i}; // will instantiate either X or a subtype | |
} | |
template<typename> | |
static auto convert(type_to_convert& t, A*) { | |
return 42; | |
} | |
}; | |
template<typename T /* same */> | |
struct with_subclasses {}; | |
template<typename T> | |
struct convert_t<with_subclasses<T>, | |
std::void_t<decltype(class_conversions::template convert<T>( | |
std::declval<type_to_convert&>(), (T*)(nullptr)))>> { | |
static auto convert(type_to_convert& t) { | |
return class_conversions::convert<T>(t, static_cast<T*>(nullptr)); | |
} | |
}; | |
template<typename T> | |
struct has_conversion { | |
template<typename U, typename = decltype(convert_t<U>::convert( | |
std::declval<type_to_convert &>()))> | |
static std::true_type test(long); | |
template<typename U> | |
static std::false_type test(int); | |
using type = decltype(test<std::remove_cv_t<T>>(0L)); | |
}; | |
template<typename T> | |
auto convert(type_to_convert&& o) { | |
using T_minus_ref = std::remove_reference_t<T>; | |
using W = with_subclasses<std::remove_const_t<T_minus_ref>>; | |
using X = has_conversion<int>::type; | |
static_assert(X::value); | |
if constexpr (has_conversion<W>::type::value) { | |
using W = with_subclasses<std::remove_const_t<T_minus_ref>>; | |
return convert_t<W>::convert(o); | |
} else { | |
return convert_t<T>::convert(o); | |
} | |
} | |
int main() { | |
std::cout << convert<int>(type_to_convert{5}) << std::endl; | |
std::cout << convert<X>(type_to_convert{6}).i << std::endl; | |
std::cout << convert<Y>(type_to_convert{6}).i << std::endl; | |
std::cout << convert<A>(type_to_convert{-1}) << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment