-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Closed
Labels
fixedSomething works now, yay!Something works now, yay!throughputMust compile fasterMust compile faster
Description
At our request, C1XX, Clang, and EDG support C++20 explicit(bool) unconditionally - i.e. in C++14/17 modes. (Like if constexpr, C1XX and Clang emit Future Technology warnings that can be suppressed.) This allows us to dramatically simplify pair, tuple, and optional.
We've requested similar support from NVIDIA's CUDA compiler. When this is available, and when MSVC can begin requiring that version of CUDA at a minimum, we should update the STL to remove our fallback codepaths.
Product code examples:
Lines 371 to 380 in 5f3e912
| // Controls whether the STL uses "conditional explicit" internally | |
| #ifndef _HAS_CONDITIONAL_EXPLICIT | |
| #ifdef __cpp_conditional_explicit | |
| #define _HAS_CONDITIONAL_EXPLICIT 1 | |
| #elif defined(__CUDACC__) || defined(__INTEL_COMPILER) | |
| #define _HAS_CONDITIONAL_EXPLICIT 0 // TRANSITION, CUDA/ICC | |
| #else // vvv C1XX or Clang or IntelliSense vvv | |
| #define _HAS_CONDITIONAL_EXPLICIT 1 | |
| #endif // ^^^ C1XX or Clang or IntelliSense ^^^ | |
| #endif // _HAS_CONDITIONAL_EXPLICIT |
Lines 184 to 207 in 5f3e912
| #if _HAS_CONDITIONAL_EXPLICIT | |
| template <class _Other1, class _Other2, | |
| enable_if_t<conjunction_v<is_constructible<_Ty1, _Other1>, is_constructible<_Ty2, _Other2>>, int> = 0> | |
| constexpr explicit(!conjunction_v<is_convertible<_Other1, _Ty1>, is_convertible<_Other2, _Ty2>>) | |
| pair(_Other1&& _Val1, _Other2&& _Val2) noexcept( | |
| is_nothrow_constructible_v<_Ty1, _Other1>&& is_nothrow_constructible_v<_Ty2, _Other2>) // strengthened | |
| : first(_STD forward<_Other1>(_Val1)), second(_STD forward<_Other2>(_Val2)) {} | |
| #else // ^^^ _HAS_CONDITIONAL_EXPLICIT ^^^ / vvv !_HAS_CONDITIONAL_EXPLICIT vvv | |
| template <class _Other1, class _Other2, | |
| enable_if_t<conjunction_v<is_constructible<_Ty1, _Other1>, is_constructible<_Ty2, _Other2>, | |
| is_convertible<_Other1, _Ty1>, is_convertible<_Other2, _Ty2>>, | |
| int> = 0> | |
| constexpr pair(_Other1&& _Val1, _Other2&& _Val2) noexcept( | |
| is_nothrow_constructible_v<_Ty1, _Other1>&& is_nothrow_constructible_v<_Ty2, _Other2>) // strengthened | |
| : first(_STD forward<_Other1>(_Val1)), second(_STD forward<_Other2>(_Val2)) {} | |
| template <class _Other1, class _Other2, | |
| enable_if_t<conjunction_v<is_constructible<_Ty1, _Other1>, is_constructible<_Ty2, _Other2>, | |
| negation<conjunction<is_convertible<_Other1, _Ty1>, is_convertible<_Other2, _Ty2>>>>, | |
| int> = 0> | |
| constexpr explicit pair(_Other1&& _Val1, _Other2&& _Val2) noexcept( | |
| is_nothrow_constructible_v<_Ty1, _Other1>&& is_nothrow_constructible_v<_Ty2, _Other2>) // strengthened | |
| : first(_STD forward<_Other1>(_Val1)), second(_STD forward<_Other2>(_Val2)) {} | |
| #endif // ^^^ !_HAS_CONDITIONAL_EXPLICIT ^^^ |
Self-contained test case demonstrating C1XX, Clang, and EDG behavior:
C:\Temp>type explicit.cpp
#include <type_traits>
using namespace std;
#ifdef __clang__
#pragma clang diagnostic ignored "-Wc++20-extensions" // warning: explicit(bool) is a C++20 extension
#else
#pragma warning(disable: 5053) // support for 'explicit(<expr>)' in C++17 and earlier is a vendor extension
#endif
struct No {};
struct Im {};
struct Ex {};
struct A {
A(Im) {}
explicit A(Ex) {}
};
template <typename T, typename Arg>
constexpr bool NotConstructible = !is_constructible_v<T, Arg> && !is_convertible_v<Arg, T>;
template <typename T, typename Arg>
constexpr bool ImplicitlyConstructible = is_constructible_v<T, Arg> && is_convertible_v<Arg, T>;
template <typename T, typename Arg>
constexpr bool ExplicitlyConstructible = is_constructible_v<T, Arg> && !is_convertible_v<Arg, T>;
static_assert(NotConstructible<A, No>, "BOOM NotConstructible");
static_assert(ImplicitlyConstructible<A, Im>, "BOOM ImplicitlyConstructible");
static_assert(ExplicitlyConstructible<A, Ex>, "BOOM ExplicitlyConstructible");
template <typename T1, typename T2> struct OldPair {
template <typename U1, typename U2,
enable_if_t<conjunction_v<is_constructible<T1, const U1&>, is_constructible<T2, const U2&>,
is_convertible<const U1&, T1>, is_convertible<const U2&, T2>>, int> = 0>
OldPair(const OldPair<U1, U2>&) {}
template <typename U1, typename U2,
enable_if_t<conjunction_v<is_constructible<T1, const U1&>, is_constructible<T2, const U2&>,
negation<conjunction<is_convertible<const U1&, T1>, is_convertible<const U2&, T2>>>>, int> = 0>
explicit OldPair(const OldPair<U1, U2>&) {}
};
static_assert(NotConstructible<OldPair<A, A>, const OldPair<No, No>&>, "OldPair BOOM 1");
static_assert(NotConstructible<OldPair<A, A>, const OldPair<No, Im>&>, "OldPair BOOM 2");
static_assert(NotConstructible<OldPair<A, A>, const OldPair<Im, No>&>, "OldPair BOOM 3");
static_assert(ImplicitlyConstructible<OldPair<A, A>, const OldPair<Im, Im>&>, "OldPair BOOM 4");
static_assert(ExplicitlyConstructible<OldPair<A, A>, const OldPair<Im, Ex>&>, "OldPair BOOM 5");
static_assert(ExplicitlyConstructible<OldPair<A, A>, const OldPair<Ex, Im>&>, "OldPair BOOM 6");
static_assert(ExplicitlyConstructible<OldPair<A, A>, const OldPair<Ex, Ex>&>, "OldPair BOOM 7");
template <typename T1, typename T2> struct NewPair {
template <typename U1, typename U2,
enable_if_t<conjunction_v<is_constructible<T1, const U1&>, is_constructible<T2, const U2&>>, int> = 0>
explicit(!is_convertible_v<const U1&, T1> || !is_convertible_v<const U2&, T2>)
NewPair(const NewPair<U1, U2>&) {}
};
static_assert(NotConstructible<NewPair<A, A>, const NewPair<No, No>&>, "NewPair BOOM 1");
static_assert(NotConstructible<NewPair<A, A>, const NewPair<No, Im>&>, "NewPair BOOM 2");
static_assert(NotConstructible<NewPair<A, A>, const NewPair<Im, No>&>, "NewPair BOOM 3");
static_assert(ImplicitlyConstructible<NewPair<A, A>, const NewPair<Im, Im>&>, "NewPair BOOM 4");
static_assert(ExplicitlyConstructible<NewPair<A, A>, const NewPair<Im, Ex>&>, "NewPair BOOM 5");
static_assert(ExplicitlyConstructible<NewPair<A, A>, const NewPair<Ex, Im>&>, "NewPair BOOM 6");
static_assert(ExplicitlyConstructible<NewPair<A, A>, const NewPair<Ex, Ex>&>, "NewPair BOOM 7");
int main() { }C:\Temp>cl /EHsc /nologo /W4 /std:c++14 explicit.cpp
explicit.cpp
C:\Temp>cl /EHsc /nologo /W4 /std:c++14 /c /BE explicit.cpp
explicit.cpp
C:\Temp>clang-cl /EHsc /nologo /W4 /std:c++14 explicit.cpp
C:\Temp>
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
fixedSomething works now, yay!Something works now, yay!throughputMust compile fasterMust compile faster