Hello, Habr.
A couple of days ago I came across this tweet:
In short: once again in C ++ they found some kind of crap that appeared there itself, emergent-convergent, like slime from one short science fiction story I read in my childhood, which accidentally arose in urban sewers and grew into a universal organic solvent.
Let's figure it out, since it will not be long (according to the text of the Standard I jumped no more than a couple of hours). And fun, links to Standard are always fun.
Here is the whole code:
#include <cstdio> class tag; template<class> struct type { friend constexpr auto get(type); }; template<class TKey, class TValue> struct set { friend constexpr auto get(TKey) { return TValue{}; } }; void foo() { // never called if constexpr(false) { // never true if (false) { // never true constexpr auto call = [](auto value) { std::printf("called %d", value); }; void(set<type<tag>, decltype(call)>{}); } } } int main() { get(type<tag>{})(42); // prints called 42 }
.
class tag;
, .
template<class> struct type { friend constexpr auto get(type); };
  type
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    . ,       get
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      -  .
 ,   (13.9.1/1) type<T>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       T
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    ?    (     ,    argument-dependent lookup,  !)    get(T)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     (9.8.1.2/3, 13.9.1/4),     (6.2/2.1).
template<class TKey, class TValue> struct set { friend constexpr auto get(TKey) { return TValue{}; } };
  set
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    . ,   ,     get
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      - .
 ,   set<K, V>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       K
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    , V
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    ?       get(K)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    ,      (6.2/2).
void foo() { if constexpr(false) { if (false) { constexpr auto call = [](auto value) { std::printf("called %d", value); }; void(set<type<tag>, decltype(call)>{}); } } }
,  if (false)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
               ,     ,    :
void foo() { if constexpr(false) { constexpr auto call = [](auto value) { std::printf("called %d", value); }; set<type<tag>, decltype(call)>{}; } }
  ,  if constexpr
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        ,         .    ?
   if constexpr
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     : 8.5.1/2.      :
If the value of the converted condition is false, the first substatement is a discarded statement
 ,    call
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      set
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     — discarded statement.   .
:
During the instantiation of an enclosing templated entity, if the condition is not value-dependent after its instantiation, the discarded substatement (if any) is not instantiated.
    discarded statement,    ,    . false
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    , ,  value-dependent,    «».     «enclosing template entity»,    enclosing entity —  foo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    ,        . ,   ,     ,  if constexpr
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       .
  .  ,  type<tag>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    ,   get(type<tag>)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       ,   ADL,    get
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        type<tag>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ( 9.8.1.2/3).   set<type<tag>, decltype(call)>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    ,    get(type<tag>)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    ,     type<tag>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .        decltype(call)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    ,    call
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       ,   C++20         (7.5.5.1/13),     .  main
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        get(type<tag>{})
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    ,       get
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       ADL.   ,  call
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    ,      ,   42.
.
,     —  discarded statement  enclosing template entity. ,   void foo()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      template<typename> void foo()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    ,       
#include <cstdio> class tag; template<class> struct type { friend constexpr auto get(type); }; template<class TKey, class TValue> struct set { friend constexpr auto get(TKey) { return TValue{}; } }; template<typename> void foo() { if constexpr(false) { // never true if (false) { // never true constexpr auto call = [](auto value) { std::printf("called %d", value); }; void(set<type<tag>, decltype(call)>{}); } } } int main() { foo<int>(); get(type<tag>{})(42); // prints called 42 }
                        :
prog.cc:23:3: error: function 'get' with deduced return type cannot be used before it is defined get(type<tag>{})(42); // prints called 42 ^ prog.cc:6:37: note: 'get' declared here struct type { friend constexpr auto get(type); }; ^
, C++ - — , ( -), ( SFINAE, detector idiom ). , - C++?
, , C++. , — , - . — - , , - - template , . , , chaotic evil. — , , , , .
Defining a friend function in a template, then referencing that function later provides a means of capturing and retrieving metaprogramming state. This technique is arcane and should be made ill-formed.
Notes from the May, 2015 meeting:
CWG agreed that such techniques should be ill-formed, although the mechanism for prohibiting them is as yet undetermined.
, — , .

, !