Skip to content

Instantly share code, notes, and snippets.

@cataphract
Last active November 12, 2020 02:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cataphract/e34b3a3bc63d8e89cfd3476c81d24219 to your computer and use it in GitHub Desktop.
Save cataphract/e34b3a3bc63d8e89cfd3476c81d24219 to your computer and use it in GitHub Desktop.
#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;
}
#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;
}
#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