Skip to content

Instantly share code, notes, and snippets.

@mpark
Created June 14, 2017 00:34
Show Gist options
  • Save mpark/c739254df16e341d520bfff8cd280958 to your computer and use it in GitHub Desktop.
Save mpark/c739254df16e341d520bfff8cd280958 to your computer and use it in GitHub Desktop.
#include <iostream>
#include <tuple>
#include <experimental/tuple>
#include <type_traits>
#include <utility>
// The same limitations apply to std::less if we wanted to figure out the winner
// of an overload resolution of `<`.
// it's a more general problem than for constructors.
template <typename T>
struct direct_init {
template <typename... Args>
auto operator()(Args &&... args) const
-> decltype(T(std::forward<Args>(args)...)) {
return T(std::forward<Args>(args)...);
}
};
template <typename T>
struct direct_list_init {
template <typename... Args>
auto operator()(Args &&... args) const
-> decltype(T{std::forward<Args>(args)...}) {
return T{std::forward<Args>(args)...};
}
};
template <typename T>
struct copy_init {
template <typename Arg>
std::enable_if_t<std::is_convertible<T, Arg &&>>,
T> operator()(Arg &&arg) const {
return std::forward<Arg>(arg);
}
};
template <typename T, typename... Args>
struct is_copy_list_initializable {
private:
static std::true_type impl(T, std::nullptr_t);
template <typename U>
static std::false_type impl(U, void *);
public:
static constexpr bool value =
decltype(impl({std::declval<Args>()...}, nullptr))::value;
};
template <typename T, typename... Args>
static constexpr bool is_copy_list_initializable_v =
is_copy_list_initializable<T, Args...>::value;
template <typename T>
struct copy_list_init {
template <typename... Args>
std::enable_if_t<is_copy_list_initializable_v<T, Args &&...>,
T> operator()(Args &&... args) const {
return {std::forward<Args>(args)...};
}
};
struct Obj {
Obj(long) { std::cout << "A" << std::endl; }
Obj(std::initializer_list<int>) { std::cout << "B" << std::endl; }
explicit Obj(int) { std::cout << "C" << std::endl; }
};
// The problem we can solve with this:
// Improving tuple & pair.. yet again... maybe... for the... last-ish time?
/*
template <typename T, typename U>
struct pair {
// BEFORE
// If `(is_convertible<X&&, T> && is_contructible<T, X&&>) &&
// (is_convertible<Y&&, U> && is_contructible<U, Y&&>)`.
template <typename X, typename Y>
pair(X &&x, Y &&y) : t(std::forward<X>(x)), u(std::forward<Y>(y)) {}
// AFTER
// If `is_convertible<X&&, T> && is_convertible<Y&&, U>`.
template <typename X, typename Y>
pair(X &&x, Y &&y)
: t(copy_init<T>{}(std::forward<X>(x))),
u(copy_init<U>{}(std::forward<Y>(y))) {}
// If we were to try to do this in language...
// If `is_convertible<X&&, T> && is_convertible<Y&&, U>`.
template <typename X, typename Y>
pair(X &&x, Y &&y) : t = std::forward<X>(x), u = std::forward<Y>(y) {}
// If `is_contructible<T, X&&> && is_constructible<T, Y&&>`
template <typename X, typename Y>
explicit pair(X &&x, Y &&y) : t(std::forward<X>(x)), u(std::forward<Y>(y)) {}
T t;
U u;
};
*/
int main() {
Obj x0(0); // direct-init
Obj x1{0}; // direct-list-init
Obj x2 = 0; // copy-init
Obj x3 = {0}; // copy-list-init
(void)x0;
(void)x1;
(void)x2;
(void)x3;
std::cout << std::endl;
direct_init<Obj>{}(0);
direct_list_init<Obj>{}(0);
copy_init<Obj>{}(0);
copy_list_init<Obj>{}(0);
std::cout << std::endl;
// std::make_from_tuple
std::experimental::apply(direct_init<Obj>{}, std::forward_as_tuple(0));
// others
std::experimental::apply(direct_list_init<Obj>{}, std::forward_as_tuple(0));
std::experimental::apply(copy_init<Obj>{}, std::forward_as_tuple(0));
std::experimental::apply(copy_list_init<Obj>{}, std::forward_as_tuple(0));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment