From: Aaryaman Sagar Date: Fri, 25 Aug 2017 23:08:18 +0000 (-0700) Subject: gcc 6.2 was not accepting the current definition of void_t X-Git-Tag: v2017.08.28.00~1 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=db9fd491eacdbef14aba095dd9ffd1b7e51e2689;p=folly.git gcc 6.2 was not accepting the current definition of void_t Summary: The current definition of void_t was leading to errors because unused template parameters are ignored and SFINAE SFIAEs Reviewed By: yfeldblum Differential Revision: D5700825 fbshipit-source-id: d23336070c217e8594980d6db710cb417b014236 --- diff --git a/folly/Traits.h b/folly/Traits.h index 20e2de91..58d507b1 100644 --- a/folly/Traits.h +++ b/folly/Traits.h @@ -172,11 +172,45 @@ using _t = typename T::type; * struct has_value_type> * : std::true_type {}; */ -#if defined(__cpp_lib_void_t) || defined(_MSC_VER) + +/** + * There is a bug in gcc that causes it to ignore unused template parameter + * arguments in template aliases and does not cause substitution failures. + * This defect has been recorded here: + * http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1558. + * + * This causes the implementation of std::void_t to be buggy, as it is likely + * defined as something like the following: + * + * template + * using void_t = void; + * + * This causes the compiler to ignore all the template arguments and does not + * help when one wants to cause substitution failures. Rather declarations + * which have void_t in orthogonal specializations are treated as the same. + * For example, assuming the possible `T` types are only allowed to have + * either the alias `one` or `two` and never both or none: + * + * template ::one>* = nullptr> + * void foo(T&&) {} + * template ::two>* = nullptr> + * void foo(T&&) {} + * + * The second foo() will be a redefinition because it conflicts with the first + * one; void_t does not cause substitution failures - the template types are + * just ignored. + * + * Till then only the non-buggy MSVC std::void_t can be used, and for the rest + * folly::void_t will continue to be used because it does not use unnamed + * template parameters for the top level implementation of void_t. + */ +#if defined(_MSC_VER) /* using override */ using std::void_t; -#else // defined(__cpp_lib_void_t) || defined(_MSC_VER) +#else // defined(_MSC_VER) namespace traits_detail { template @@ -188,7 +222,7 @@ struct void_t_ { template using void_t = _t>; -#endif // defined(__cpp_lib_void_t) || defined(_MSC_VER) +#endif // defined(_MSC_VER) /** * IsRelocatable::value describes the ability of moving around @@ -386,11 +420,11 @@ struct Bools { // Lighter-weight than Conjunction, but evaluates all sub-conditions eagerly. template -struct StrictConjunction - : std::is_same, Bools<(Ts::value || true)...>> {}; +struct StrictConjunction + : std::is_same, Bools<(Ts::value || true)...>> {}; template -struct StrictDisjunction +struct StrictDisjunction : Negation< std::is_same, Bools<(Ts::value && false)...>> > {};