Path: blob/master/src/hotspot/share/metaprogramming/enableIf.hpp
40930 views
/*1* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#ifndef SHARE_METAPROGRAMMING_ENABLEIF_HPP25#define SHARE_METAPROGRAMMING_ENABLEIF_HPP2627#include "metaprogramming/logical.hpp"28#include <type_traits>2930// Retained temporarily for backward compatibility.31// For function template SFINAE, use the ENABLE_IF macro below.32// For class template SFINAE, use std::enable_if_t directly.33template<bool cond, typename T = void>34using EnableIf = std::enable_if<cond, T>;3536// ENABLE_IF(Condition...)37// ENABLE_IF_SDEFN(Condition...)38//39// The ENABLE_IF macro can be used in a function template parameter list to40// control the presence of that overload via SFINAE.41//42// When the declaration and definition of a function template are separate,43// only the declaration can use ENABLE_IF in the template parameter list.44// The definition should instead use ENABLE_IF_SDEFN with an _equivalent_45// (C++14 14.4 and 14.5.6.1) Condition for the corresponding template46// parameter. ("SDEFN" is short for "SEPARATE_DEFINITION".)47//48// Condition must be a constant expression whose value is convertible to49// bool. The Condition is captured as a variadic macro parameter so that it50// may contain unparenthesized commas.51//52// An example of the usage of the ENABLE_IF macro is53//54// template<typename T,55// ENABLE_IF(std::is_integral<T>::value),56// ENABLE_IF(std::is_signed<T>::value)>57// void foo(T x) { ... }58//59// That definition will not be considered in a call to foo unless T is a60// signed integral type.61//62// An alternative to two ENABLE_IF parameters would be single parameter63// that is a conjunction of the expressions. The benefit of multiple64// ENABLE_IF parameters is the compiler may provide more information in65// certain error contexts.66//67// Details:68//69// With C++98/03 there are 2 ways to use enable_if with function templates:70//71// (1) As the return type72// (2) As an extra parameter73//74// C++11 adds another way, using an extra anonymous non-type template75// parameter with a default value, i.e.76//77// std::enable_if_t<CONDITION, int> = 078//79// (The left-hand side is the 'int' type of the anonymous parameter. The80// right-hand side is the default value. The use of 'int' and '0' are81// conventional; the specific type and value don't matter, so long as they82// are compatible.)83//84// Compared to (1) this has the benefit of less cluttered syntax for the85// function signature. Compared to (2) it avoids polluting the signature86// with dummy extra parameters. And there are cases where this new approach87// can be used while neither of the others is even possible.88//89// Using an extra template parameter is somewhat syntactically complex, with90// a number of details to get right. However, that complexity can be91// largely hidden using a macro, resulting in more readable uses of SFINAE92// for function templates.93//94// One of those details is that a function template definition that is95// separate from its declaration cannot have a default value. Thus,96// ENABLE_IF can't be used in such a definition. But the type expression in97// the separate definition must be equivalent (C++14 14.4 and 14.5.6.1) to98// that in the declation. The ENABLE_IF_SDEFN macro provides the common99// code for the separate definition that must match the corresponding100// declaration code at the token level.101//102// The Condition must be wrapped in parenthesis in the expansion. Otherwise,103// a '>' operator in the expression may be misinterpreted as the end of the104// template parameter list. But rather than simply wrapping in parenthesis,105// Condition is wrapped in an explicit conversion to bool, so the value need106// not be *implicitly* convertible.107//108// There is a problem when Condition is not dependent on any template109// parameter. Such a Condition will be evaluated at template definition110// time, as part of template type checking. If Condition is false, that111// will result in a compile-time error rather than the desired SFINAE112// exclusion. This situation is sufficiently rare that no additional113// macro support is provided for it. (One solution is to add a new114// type parameter defaulted to the type being checked in Condition, and115// use that new parameter instead in Condition. There is an automatic116// macro-based solution, but it involves the __COUNTER__ extension.)117//118// Some references suggest a different approach to using a template119// parameter for SFINAE. An anonymous type parameter with a default type120// that uses std::enable_if can also be used in some cases, i.e.121//122// typename = std::enable_if_t<CONDITION>123//124// However, this doesn't work when there are overloads that need to be125// selected amongst via SFINAE. Two signatures that differ only in a126// template parameter default are not distinct overloads, they are multiple127// definitions of the same function.128//129// Some versions of gcc permit ENABLE_IF to be used in some separate130// definitions. Other toolchains reject such usage.131//132// The expansion of ENABLE_IF doesn't use ENABLE_IF_SDEFN (or both use a133// common helper) because of issues with the Visual Studio preprocessor's134// handling of variadic macros.135136#define ENABLE_IF(...) \137std::enable_if_t<bool(__VA_ARGS__), int> = 0138139#define ENABLE_IF_SDEFN(...) \140std::enable_if_t<bool(__VA_ARGS__), int>141142#endif // SHARE_METAPROGRAMMING_ENABLEIF_HPP143144145