рджреЛрд╕реНрддреЛрдВ рд╕реЗ рдХреНрдпреЛрдВ рдмрдЪреЗрдВ, рдпрд╛ рдореИрдВрдиреЗ рдЕрдкрдиреЗ рд╕рднреА рдлрд╛рдпрджреЗ рдХреИрд╕реЗ рдЦреЛ рджрд┐рдП

рд╣рд╛рдп, рд╣реИрдмреНрд░ред


рдХреБрдЫ рджрд┐рди рдкрд╣рд▓реЗ рдореИрдВ рдЗрд╕ рдЯреНрд╡реАрдЯ рдкрд░ рдЖрдпрд╛:



рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ: C ++ рдореЗрдВ рдПрдХ рдмрд╛рд░ рдлрд┐рд░ рдЙрдиреНрд╣реЗрдВ рдХреБрдЫ рдРрд╕реА рдмрдХрд╡рд╛рд╕ рд▓рдЧреАрдВ, рдЬреЛ рдЦреБрдж рд╡рд╣рд╛рдВ рджрд┐рдЦрд╛рдИ рджреАрдВ, рдЙрднрд░рддреА-рд╕рдВрд╡рд░рддреА рд╣реБрдИрдВ, рдЬреИрд╕реЗ рдХрд┐ рдореИрдВ рдЕрдкрдиреЗ рдмрдЪрдкрди рдореЗрдВ рдкрдврд╝реА рдЧрдИ рдПрдХ рд▓рдШреБ рд╡рд┐рдЬреНрдЮрд╛рди рдХрдерд╛ рд╕реЗ, рдЬреЛ рдЧрд▓рддреА рд╕реЗ рд╢рд╣рд░реА рд╕реАрд╡рд░ рдореЗрдВ рдкреИрджрд╛ рд╣реБрдИ рдФрд░ рдПрдХ рд╕рд╛рд░реНрд╡рднреМрдорд┐рдХ рдХрд╛рд░реНрдмрдирд┐рдХ рд╡рд┐рд▓рд╛рдпрдХ рдореЗрдВ рд╡рд┐рдХрд╕рд┐рдд рд╣реБрдИред


рдЪрд▓реЛ рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рддреЗ рд╣реИрдВ, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рд▓рдВрдмреЗ рд╕рдордп рддрдХ рдирд╣реАрдВ рд╣реЛрдЧрд╛ (рдорд╛рдирдХ рдХреЗ рдкрд╛рда рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдореИрдВрдиреЗ рдПрдХ-рджреЛ рдШрдВрдЯреЗ рд╕реЗ рдЕрдзрд┐рдХ рдирд╣реАрдВ рдЫрд▓рд╛рдВрдЧ рд▓рдЧрд╛рдИ)ред рдФрд░ рдордЬреЗрджрд╛рд░, рд╕реНрдЯреИрдВрдбрд░реНрдб рдХреЗ рд▓рд┐рдВрдХ рд╣рдореЗрд╢рд╛ рдордЬреЗрджрд╛рд░ рд╣реЛрддреЗ рд╣реИрдВред


рдпрд╣рд╛рдБ рдкреВрд░рд╛ рдХреЛрдб рд╣реИ:


#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. тАФ , , , , .


, . - C++14, C++11, 03.


? :


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.

, тАФ , .


тАФ , ?


, !

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


All Articles