make common_type SFINAE-friendly and support void. Patch from Agustin Berge.

This patch also fixes PR22135. (https://llvm.org/bugs/show_bug.cgi?id=22135)
See the review for more information: http://reviews.llvm.org/D6964

llvm-svn: 246977
This commit is contained in:
Eric Fiselier 2015-09-08 00:13:57 +00:00
parent bb9a6ccfa8
commit 21dfbfb426
2 changed files with 95 additions and 24 deletions

View File

@ -1517,21 +1517,19 @@ public:
template <class _Tp, class _Up>
struct _LIBCPP_TYPE_VIS_ONLY common_type<_Tp, _Up, void>
{
private:
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
static _Tp&& __t();
static _Up&& __u();
#else // _LIBCPP_HAS_NO_RVALUE_REFERENCES
static _Tp __t();
static _Up __u();
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
public:
typedef typename remove_reference<decltype(true ? __t() : __u())>::type type;
typedef typename decay<decltype(
true ? _VSTD::declval<_Tp>() : _VSTD::declval<_Up>()
)>::type type;
};
#else // _LIBCPP_HAS_NO_VARIADICS
template <class ..._Tp> struct common_type;
// bullet 1 - sizeof...(Tp) == 0
template <class ..._Tp>
struct _LIBCPP_TYPE_VIS_ONLY common_type {};
// bullet 2 - sizeof...(Tp) == 1
template <class _Tp>
struct _LIBCPP_TYPE_VIS_ONLY common_type<_Tp>
@ -1539,22 +1537,45 @@ struct _LIBCPP_TYPE_VIS_ONLY common_type<_Tp>
typedef typename decay<_Tp>::type type;
};
// bullet 3 - sizeof...(Tp) == 2
template <class _Tp, class _Up, class = void>
struct __common_type2 {};
template <class _Tp, class _Up>
struct __common_type2<_Tp, _Up,
typename __void_t<decltype(
true ? _VSTD::declval<_Tp>() : _VSTD::declval<_Up>()
)>::type>
{
typedef typename decay<decltype(
true ? _VSTD::declval<_Tp>() : _VSTD::declval<_Up>()
)>::type type;
};
template <class _Tp, class _Up>
struct _LIBCPP_TYPE_VIS_ONLY common_type<_Tp, _Up>
: __common_type2<_Tp, _Up> {};
// bullet 4 - sizeof...(Tp) > 2
template <class ...Tp> struct __common_types;
template <class, class = void>
struct __common_type_impl {};
template <class _Tp, class _Up, class ..._Vp>
struct __common_type_impl<__common_types<_Tp, _Up, _Vp...>,
typename __void_t<typename common_type<_Tp, _Up>::type>::type>
{
private:
static _Tp&& __t();
static _Up&& __u();
static bool __f();
public:
typedef typename decay<decltype(__f() ? __t() : __u())>::type type;
typedef typename common_type<
typename common_type<_Tp, _Up>::type, _Vp...
>::type type;
};
template <class _Tp, class _Up, class ..._Vp>
struct _LIBCPP_TYPE_VIS_ONLY common_type<_Tp, _Up, _Vp...>
{
typedef typename common_type<typename common_type<_Tp, _Up>::type, _Vp...>::type type;
};
: __common_type_impl<__common_types<_Tp, _Up, _Vp...> > {};
#if _LIBCPP_STD_VER > 11
template <class ..._Tp> using common_type_t = typename common_type<_Tp...>::type;

View File

@ -13,11 +13,39 @@
#include <type_traits>
#include "test_macros.h"
struct E {};
template <class T>
struct X { explicit X(T const&){} };
template <class T>
struct S { explicit S(T const&){} };
namespace std
{
template <typename T>
struct common_type<T, ::S<T> >
{
typedef S<T> type;
};
}
#if TEST_STD_VER >= 11
template <class T, class U, class = void>
struct no_common_type : std::true_type {};
template <class T, class U>
struct no_common_type<T, U, typename std::conditional<false,
typename std::common_type<T, U>::type, void>::type> : std::false_type {};
#endif // TEST_STD_VER >= 11
int main()
{
static_assert((std::is_same<std::common_type<int>::type, int>::value), "");
static_assert((std::is_same<std::common_type<char>::type, char>::value), "");
#if _LIBCPP_STD_VER > 11
#if TEST_STD_VER > 11
static_assert((std::is_same<std::common_type_t<int>, int>::value), "");
static_assert((std::is_same<std::common_type_t<char>, char>::value), "");
#endif
@ -29,7 +57,7 @@ int main()
static_assert((std::is_same<std::common_type<int, int>::type, int>::value), "");
static_assert((std::is_same<std::common_type<int, const int>::type, int>::value), "");
static_assert((std::is_same<std::common_type<long, const int>::type, long>::value), "");
static_assert((std::is_same<std::common_type<const long, int>::type, long>::value), "");
static_assert((std::is_same<std::common_type<long, volatile int>::type, long>::value), "");
@ -38,15 +66,37 @@ int main()
static_assert((std::is_same<std::common_type<double, char>::type, double>::value), "");
static_assert((std::is_same<std::common_type<short, char>::type, int>::value), "");
#if _LIBCPP_STD_VER > 11
#if TEST_STD_VER > 11
static_assert((std::is_same<std::common_type_t<double, char>, double>::value), "");
static_assert((std::is_same<std::common_type_t<short, char>, int>::value), "");
#endif
static_assert((std::is_same<std::common_type<double, char, long long>::type, double>::value), "");
static_assert((std::is_same<std::common_type<unsigned, char, long long>::type, long long>::value), "");
#if _LIBCPP_STD_VER > 11
#if TEST_STD_VER > 11
static_assert((std::is_same<std::common_type_t<double, char, long long>, double>::value), "");
static_assert((std::is_same<std::common_type_t<unsigned, char, long long>, long long>::value), "");
#endif
static_assert((std::is_same<std::common_type< void>::type, void>::value), "");
static_assert((std::is_same<std::common_type<const void>::type, void>::value), "");
static_assert((std::is_same<std::common_type< volatile void>::type, void>::value), "");
static_assert((std::is_same<std::common_type<const volatile void>::type, void>::value), "");
static_assert((std::is_same<std::common_type<void, const void>::type, void>::value), "");
static_assert((std::is_same<std::common_type<const void, void>::type, void>::value), "");
static_assert((std::is_same<std::common_type<void, volatile void>::type, void>::value), "");
static_assert((std::is_same<std::common_type<volatile void, void>::type, void>::value), "");
static_assert((std::is_same<std::common_type<const void, const void>::type, void>::value), "");
#if TEST_STD_VER >= 11
static_assert((no_common_type<void, int>::value), "");
static_assert((no_common_type<int, void>::value), "");
static_assert((no_common_type<int, E>::value), "");
static_assert((no_common_type<int, X<int> >::value), "");
#endif // TEST_STD_VER >= 11
static_assert((std::is_same<std::common_type<int, S<int> >::type, S<int> >::value), "");
static_assert((std::is_same<std::common_type<int, S<int>, S<int> >::type, S<int> >::value), "");
static_assert((std::is_same<std::common_type<int, int, S<int> >::type, S<int> >::value), "");
}