Implementation of CONCEPT_REQUIRES_ in ranges-v3

Trying to learn how to use the Eric Niebler range-v3 library and read the source code, I saw that the macro definition:

#define CONCEPT_PP_CAT_(X, Y) X ## Y #define CONCEPT_PP_CAT(X, Y) CONCEPT_PP_CAT_(X, Y) /// \addtogroup group-concepts /// @{ #define CONCEPT_REQUIRES_(...) \ int CONCEPT_PP_CAT(_concept_requires_, __LINE__) = 42, \ typename std::enable_if< \ (CONCEPT_PP_CAT(_concept_requires_, __LINE__) == 43) || (__VA_ARGS__), \ int \ >::type = 0 \ /**/ 

So, in short, the definition of a type template is:

 template<typename I, typename O, CONCEPT_REQUIRES_(InputIterator<I>() && WeaklyIncrementable<O>())> void fun_signature() {} 

translates as:

 template<typename I, typename O, int a_unique_name = 42, typename std::enable_if <false || (InputIterator<I>() && WeaklyIncrementable<O>()), int>::type = 0 > void fun_signature() {} 

I would like to know why this macro implements this path. Why is this integer necessary and why does it need false || cond false || cond , not just the cond template argument?

+5
source share
1 answer

template definition, for example ... translates to ...

To close. It actually means:

 template<typename I, typename O, int a_unique_name = 42, typename std::enable_if <a_unique_name == 43 || (InputIterator<I>() && WeaklyIncrementable<O>()), int>::type = 0 > void fun_signature() {} 

A unique int name exists to ensure that the condition for enable_if dependent on the template parameter to exclude the condition being checked during template definition and not during instance creation so that SFINAE can happen. Consider this class definition:

 template<class T> struct S { template<class U, CONCEPT_REQUIRES_(ranges::Integral<T>())> void f(U); }; 

without an injected unique int , this definition will be lower:

 template<class T> struct S { template<class U, std::enable_if_t<ranges::Integral<T>()>> void f(U); }; 

and since ranges::Integral<T>() is independent of the template parameter of this function, compilers will diagnose that std::enable_if_t<ranges::Integral<T>()> - which drops to typename std::enable_if<ranges::Integral<T>()>::type is poorly formed because std::enable_if<false> does not contain a member named type , With injected-unique- int , the class definition is reduced to:

 template<class T> struct S { template<class U, int some_unique_name = 42, std::enable_if_t<some_unique_name == 43 || ranges::Integral<T>()>> void f(U); }; 

now the compiler cannot analyze enable_if_t during template definition, since some_unique_name is a template parameter that the user can specify as 43 .

+5
source

Source: https://habr.com/ru/post/1271241/


All Articles