Spec-Zone.ru › C++

Операторы доступа к членам

Обеспечивает доступ к члену своего операнда.

Название оператора Синтаксис Допускает перегрузку Примеры прототипов (для classT)
В определении класса Вне определения класса
индексация a[b] Да R& T::operator[](S b); Н/Д
a[...] (начиная с C++23) R& T::operator[](...);
разыменование *a Да R& T::operator*(); R& operator*(T a);
взятие адреса &a Да R* T::operator&(); R* operator&(T a);
член объекта a.b Нет Н/Д Н/Д
член указателя a->b Да R* T::operator->(); Н/Д
указатель на член объекта a.*b Нет Н/Д Н/Д
указатель на член указателя a->*b Да R& T::operator->*(S b); R& operator->*(T a, S b);
Примечания
  • Как и для большинства пользовательских перегрузок, типы возвращаемых значений должны соответствовать типам, возвращаемым встроенными операторами, чтобы пользовательские операторы можно было использовать так же, как встроенные. Однако в пользовательской перегрузке оператора в качестве возвращаемого типа можно использовать любой тип (включая void). Исключение — operator->: для практического использования он должен возвращать указатель или другой класс с перегруженным operator->.

Пояснение

Встроенный оператор индексации обеспечивает доступ к объекту, на который указывает операнд-указатель или операнд-массив.

Встроенный оператор разыменования обеспечивает доступ к объекту или функции, на которые указывает операнд-указатель.

Встроенный оператор взятия адреса создаёт указатель, указывающий на объект или функцию-операнд.

Операторы члена объекта и указателя на член объекта обеспечивают доступ к члену данных или функции-члену операнда-объекта.

Встроенные операторы члена указателя и указателя на член указателя обеспечивают доступ к члену данных или функции-члену класса, на который указывает операнд-указатель.

Встроенный оператор индексации

Выражения с оператором индексации имеют вид

expr1 [expr2 ] (1)
expr1 [{expr , ...}] (2) (начиная с C++11)
expr1 [expr2 , expr , ...] (3) (начиная с C++23)
1) Для встроенного оператора одно из выражений (либо expr1, либо expr2) должно быть гл-значением типа «массив из T» или пр-значением типа «указатель на T», а другое выражение (expr2 или expr1 соответственно) должно быть пр-значением нескоупированного перечислимого или целочисленного типа. Тип результата этого выражения — T. expr2 не может быть не заключённым в скобки выражением с оператором запятая.(начиная с C++23)
2) Форма с заключённым в фигурные скобки списком внутри квадратных скобок используется только для вызова перегруженного operator[].
3) Форма со списком выражений, разделённых запятыми, внутри квадратных скобок используется только для вызова перегруженного operator[].

Встроенное выражение индексации E1[E2] в точности тождественно выражению *(E1 + E2), за исключением категории значения (см. ниже) и порядка вычисления(начиная с C++17): операнд-указатель (который может быть результатом преобразования массива в указатель и должен указывать на элемент массива или на позицию сразу за его последним элементом) корректируется так, чтобы указывать на другой элемент того же массива согласно правилам арифметики указателей, после чего выполняется разыменование.

При применении к массиву выражение индексации является lvalue, если массив является lvalue, и xvalue, если это не так(начиная с C++11).

При применении к указателю выражение индексации всегда является lvalue.

Тип T не может быть неполным типом, даже если размер или внутренняя структура T никогда не используются, как в &x[0].

Использование не заключённого в скобки выражения с оператором запятая в качестве второго (правого) аргумента оператора индексации объявлено устаревшим.

Например, a[b, c] объявлено устаревшим, а a[(b, c)] — нет.

(начиная с C++20)
(до C++23 включительно)

Не заключённое в скобки выражение с оператором запятая не может быть вторым (правым) аргументом оператора индексации. Например, a[b, c] либо некорректно, либо эквивалентно a.operator[](b, c).

Чтобы использовать выражение с оператором запятая в качестве индекса, необходимы скобки, например a[(b, c)].

(начиная с C++23)

При разрешении перегрузки для пользовательских операторов для каждого типа объекта T (возможно, с квалификаторами cv) в разрешении перегрузки участвует следующая сигнатура функции:

T& operator[](T*, std::ptrdiff_t);
T& operator[](std::ptrdiff_t, T*);
#include <iostream>
#include <map>
#include <string>

int main()
{
    int a[4] = {1, 2, 3, 4};
    int* p = &a[2];
    std::cout << p[1] << p[-1] << 1[p] << (-1)[p] << '\n';
    
    std::map<std::pair<int, int>, std::string> m;
    m[{1, 2}] = "abc"; // uses the [{...}] version
}

Вывод:

4242

Встроенный оператор разыменования

Выражения с оператором разыменования имеют вид

*expr

Операндом встроенного оператора разыменования должен быть указатель на объект или указатель на функцию; результатом является lvalue, ссылающееся на объект или функцию, на которые указывает expr. Если expr в действительности не указывает на объект или функцию, поведение не определено (кроме случая, указанного для typeid).

Указатель на (возможно, cv-квалифицированный) void разыменовать нельзя. Указатели на другие неполные типы разыменовывать можно, однако результирующее lvalue может использоваться только в контекстах, допускающих lvalue неполного типа, например при инициализации ссылки.

При разрешении перегрузки для пользовательских операторов для каждого типа T, который является типом объекта (возможно, с квалификаторами cv) или типом функции (без квалификаторов const или ref), в разрешении перегрузки участвует следующая сигнатура функции:

T& operator*(T*);
#include <iostream>

int f() { return 42; }

int main()
{
    int n = 1;
    int* pn = &n;
    
    int& r = *pn; // lvalue can be bound to a reference
    int m = *pn;  // indirection + lvalue-to-rvalue conversion
    
    int (*fp)() = &f;
    int (&fr)() = *fp; // function lvalue can be bound to a reference
    
    [](...){}(r, m, fr); // removes possible "unused variable" warnings
}

Встроенный оператор взятия адреса

Выражения с оператором взятия адреса имеют вид

&expr (1)
&class ::member (2)
&splice-specifier (3) (начиная с C++26)
1) Если операнд является выражением-lvalue некоторого типа объекта или функции T, operator& создаёт и возвращает пр-значение типа T* с теми же квалификаторами cv, указывающее на объект или функцию, обозначенные операндом. Если операнд имеет неполный тип, указатель сформировать можно, однако если этим неполным типом окажется класс, определяющий собственный operator&, не определено, будет использован встроенный оператор или перегрузка. Для операндов типа с пользовательским operator& можно использовать std::addressof, чтобы получить настоящий указатель.

Обратите внимание: в отличие от C99 и более поздних версий C, здесь нет особого случая для применения унарного оператора & к результату унарного оператора *.

Если expr обозначает функцию-член с явным объектом, expr должен быть квалифицированным идентификатором. Применение & к неквалифицированному идентификатору, обозначающему функцию-член с явным объектом, некорректно.

(начиная с C++23)
2) Если операнд является квалифицированным именем нестатического члена или вариантного члена, отличного от функции-члена с явным объектом(начиная с C++23), например &C::member, результатом является пр-значение — указатель на функцию-член или указатель на член данных типа T класса C. Обратите внимание: ни &member, ни C::member, ни даже &(C::member) нельзя использовать для инициализации указателя на член.
3) Если операнд является спецификатором splice, результатом является указатель на член, если он обозначает нестатический член; в противном случае результатом является указатель на объект или функцию, обозначающие соответствующий объект или функцию. Выражение некорректно, если не заключённый в скобки спецификатор splice обозначает член анонимного объединения. Обратите внимание: &([:r:]) никогда не является указателем на член.

Если операнд обозначает перегруженную функцию или шаблон функции, адрес можно получить только в том случае, если перегрузку можно разрешить исходя из контекста. Подробности см. в разделе Адрес перегруженной функции.

При разрешении перегрузки для пользовательских операторов этот оператор не добавляет никаких дополнительных сигнатур функций: встроенный оператор взятия адреса не применяется, если существует перегруженный operator&, являющийся подходящей функцией.

void f(int) {}
void f(double) {}

struct A { int i; };
struct B { void f(); };

int main()
{
    int n = 1;
    int* pn = &n;    // pointer
    int* pn2 = &*pn; // pn2 == pn
    
    int A::* mp = &A::i;      // pointer to data member
    void (B::*mpf)() = &B::f; // pointer to member function
    
    void (*pf)(int) = &f; // overload resolution due to initialization context
//  auto pf2 = &f; // error: ambiguous overloaded function type
    auto pf2 = static_cast<void (*)(int)>(&f); // overload resolution due to cast
}

Встроенные операторы доступа к членам

Выражения с оператором доступа к члену имеют вид

expr . template(необязательно) id-expr (1)
expr -> template(необязательно) id-expr (2)
expr . splice-specifier (3) (начиная с C++26)
expr -> splice-specifier (3) (начиная с C++26)
1) expr должно быть выражением полного типа класса T, если только id-expr не обозначает псевдодеструктор (см. ниже).
Если id-expr обозначает статический член или элемент перечисления, expr является выражением с отбрасываемым значением.
2) expr должно быть выражением типа «указатель на полный тип класса» T*, если только id-expr не обозначает псевдодеструктор (см. ниже).

id-expr — это имя (формально — выражение-идентификатор, обозначающее) члена T или однозначного и доступного базового класса B типа T (например, E1.E2 или E1->E2), возможно, квалифицированное (например, E1.B::E2 или E1->B::E2), а также, возможно, содержащее дизамбигуатор template (например, E1.template E2 или E1->template E2).

splice-specifier — это splice-выражение, обозначающее член T или однозначного и доступного базового класса B типа T либо отношение прямого базового класса (то есть элемент std::meta::bases_of(^^T, ctx)).

(начиная с C++26)

Если вызывается пользовательский operator->, к полученному значению рекурсивно снова применяется operator->, пока не будет достигнут operator->, возвращающий обычный указатель. После этого к этому указателю применяются встроенные правила.

Для встроенных типов выражение E1->E2 в точности эквивалентно (*E1).E2; поэтому следующие правила относятся только к E1.E2.

В выражении E1.E2:

1) Если E2 является статическим членом данных:
  • Если E2 имеет ссылочный тип T& или T&&(начиная с C++11), результатом является lvalue типа T, обозначающее объект или функцию, на которые привязана ссылка.
  • В противном случае, если тип E2 обозначить как T, результатом является lvalue типа T, обозначающее этот статический член данных.
В обоих случаях E1 вычисляется, а результат отбрасывается.
2) Если E2 является нестатическим членом данных:
  • Если E2 имеет ссылочный тип T& или T&&(начиная с C++11), результатом является lvalue типа T, обозначающее объект или функцию, на которые привязан соответствующий ссылочный член E1.
  • В противном случае, если E1 является lvalue, результатом является lvalue, обозначающее этот нестатический член данных E1.
  • В противном случае (если E1 является rvalue(до C++17 включительно)xvalue (которое может быть материализовано из пр-значения)(начиная с C++17)), результатом является rvalue(до C++11 включительно)xvalue(начиная с C++11), обозначающее этот нестатический член данных E1.
Если E2 не является членом mutable, cv-квалификация результата является объединением cv-квалификаций E1 и E2; в противном случае (если E2 является членом mutable) она является объединением volatile-квалификаций E1 и E2.
3) Если E2 является набором перегрузок (содержащим одну или несколько статических функций-членов и нестатических функций-членов), E1.E2 должен быть (возможно, заключённым в скобки) левым операндом оператора вызова функции-члена, а для выбора функции, к которой относится E2, используется разрешение перегрузки функций. После этого:
  • Если E2 является статической функцией-членом, результатом является lvalue, обозначающее эту статическую функцию-член. В этом случае E1 вычисляется, а результат отбрасывается.
  • В противном случае (E2 является нестатической функцией-членом) результатом является пр-значение, обозначающее эту нестатическую функцию-член E1.
4) Если E2 является элементом перечисления-члена, а тип E2 обозначить как T, результатом является rvalue(до C++11 включительно)пр-значение(начиная с C++11) типа T, значение которого совпадает со значением элемента перечисления.
5) Если E2 является вложенным типом, программа некорректна.
6) Если E2 обозначает отношение прямого базового класса, результат обозначает соответствующий подобъект прямого базового класса в E1.
struct B { int b; };
struct C : B { int get() const { return b; } };
struct D : B, C {};
constexpr int f() {
    D d = {1, {}};

    constexpr auto ctx = std::meta::access_context::current();

    // b unambiguously refers to the direct base class of type B,
    // not the indirect base class of type B
    B& b = d.[: std::meta::bases_of(^^D, ctx)[0] :];
    b.b += 10;
    return 10 * b.b + d.get();
}

static_assert(f() == 110);
(начиная с C++26)
7) Если E1 имеет тип ScalarType, а E2 — это ~, за которым следует имя типа или спецификатор decltype, обозначающий тот же тип (без учёта cv-квалификаторов), возможно, квалифицированный, результатом является особый вид пр-значения, который можно использовать только как левый операнд оператора вызова функции и ни для каких других целей.
Полученное выражение вызова функции называется вызовом псевдодеструктора. Оно не принимает аргументов, возвращает void, вычисляет E1 и завершает время жизни своего результирующего объекта. Это единственный случай, когда левый операнд оператора . имеет неклассовый тип. Возможность вызова псевдодеструктора позволяет писать код, не выясняя, существует ли деструктор для заданного типа.

operator. нельзя перегружать, а для operator-> при разрешении перегрузки для пользовательских операторов встроенный оператор не добавляет никаких дополнительных сигнатур функций: встроенный operator-> не применяется, если существует перегруженный operator->, являющийся подходящей функцией.

#include <cassert>
#include <iostream>
#include <memory>

struct P
{
    template<typename T>
    static T* ptr() { return new T; }
};

template<typename T>
struct A
{
    A(int n): n(n) {}
    
    int n;
    static int sn;
    
    int f() { return 10 + n; }
    static int sf() { return 4; }
    
    class B {};
    enum E {RED = 1, BLUE = 2};
    
    void g()
    {
        typedef int U;
        
        // keyword template needed for a dependent template member
        int* p = T().template ptr<U>();
        p->~U(); // U is int, calls int's pseudo destructor
        delete p;
    }
};

template<>
int A<P>::sn = 2;

struct UPtrWrapper
{
    std::unique_ptr<std::string> uPtr;
    std::unique_ptr<std::string>& operator->() { return uPtr; }
};

int main()
{
    A<P> a(1);
    std::cout << a.n << ' '
              << a.sn << ' '   // A::sn also works
              << a.f() << ' ' 
              << a.sf() << ' ' // A::sf() also works
//            << &a.f << ' '   // error: ill-formed if a.f is not the
                               // left-hand operand of operator()
//            << a.B << ' '    // error: nested type not allowed
              << a.RED << ' '; // enumerator
    
    UPtrWrapper uPtrWrap{std::make_unique<std::string>("wrapped")};
    assert(uPtrWrap->data() == uPtrWrap.operator->().operator->()->data());
}

Вывод:

1 2 11 4 1

Если E2 является нестатическим членом или отношением прямого базового класса(начиная с C++26), а результат E1 — это объект, тип которого не подобен типу E1, поведение не определено:

struct A { int i; };
struct B { int j; };
struct D : A, B {};

void f()
{
    D d;
    static_cast<B&>(d).j;      // OK, object expression designates the B subobject of d
    reinterpret_cast<B&>(d).j; // undefined behavior
}

Встроенные операторы доступа через указатель на член

Выражения доступа к члену через указатели на члены имеют вид

lhs .*rhs (1)
lhs ->*rhs (2)
1) lhs должно быть выражением типа класса T.
2) lhs должно быть выражением типа «указатель на тип класса» T*.

rhs должно быть rvalue типа «указатель на член» (данных или функцию) типа T либо указателем на член однозначного и доступного базового класса B типа T.

Для встроенных типов выражение E1->*E2 в точности эквивалентно (*E1).*E2; поэтому следующие правила относятся только к E1.*E2.

В выражении E1.*E2:

1) если E2 является указателем на член данных,
  • если E1 является lvalue, результатом является lvalue, обозначающее этот член данных;
  • в противном случае (если E1 является rvalue(до C++17 включительно)xvalue (которое может быть материализовано из пр-значения)(начиная с C++17)), результатом является rvalue(до C++11 включительно)xvalue(начиная с C++11), обозначающее этот член данных;
2) если E2 является указателем на функцию-член, результатом является особый вид пр-значения, обозначающий эту функцию-член, который можно использовать только как левый операнд оператора вызова функции-члена и ни для каких других целей;
3) правила cv-квалификации такие же, как для оператора доступа к члену объекта, с одним дополнительным правилом: указатель на член, обозначающий член mutable, нельзя использовать для изменения этого члена в константном объекте;
4) если E2 является нулевым значением указателя на член, поведение не определено;
5) если результат E1 является объектом, тип которого не подобен типу E1, либо его наиболее производный объект не содержит член, на который ссылается E2, поведение не определено;
6) если E1 является rvalue, а E2 указывает на функцию-член с ref-квалификатором &, программа некорректна если только функция-член не имеет cv-квалификатор const, но не volatile(начиная с C++20);
7) если E1 является lvalue, а E2 указывает на функцию-член с ref-квалификатором &&, программа некорректна. (начиная с C++11)

При разрешении перегрузки для определённых пользователем операторов для каждой комбинации типов D, B, R, где тип класса B является либо тем же классом, что и D, либо однозначным и доступным базовым классом D, а R является типом объекта или функции, в разрешении перегрузки участвует следующая сигнатура функции:

R& operator->*(D*, R B::*);

Оба операнда могут иметь cv-квалификаторы; в этом случае cv-квалификация возвращаемого типа представляет собой объединение cv-квалификаций операндов.

#include <iostream>

struct S
{
    S(int n) : mi(n) {}
    mutable int mi;
    int f(int n) { return mi + n; }
};

struct D : public S
{
    D(int n) : S(n) {}
};

int main()
{
    int S::* pmi = &S::mi;
    int (S::* pf)(int) = &S::f;
    
    const S s(7);
//  s.*pmi = 10; // error: cannot modify through mutable
    std::cout << s.*pmi << '\n';
    
    D d(7); // base pointers work with derived object
    D* pd = &d;
    std::cout << (d.*pf)(7) << ' '
              << (pd->*pf)(8) << '\n';
}

Вывод:

7
14 15

Стандартная библиотека

Оператор индексирования перегружен во многих классах стандартных контейнеров:

operator[]
доступ к указанному биту
(открытая функция-член std::bitset<N>)
operator[]
индексированный доступ к управляемому массиву
(открытая функция-член std::unique_ptr<T,Deleter>)
operator[]
доступ к указанному символу
(открытая функция-член std::basic_string<CharT,Traits,Allocator>)
operator[]
доступ к указанному элементу
(открытая функция-член std::array<T,N>)
operator[]
доступ к указанному элементу
(открытая функция-член std::deque<T,Allocator>)
operator[]
доступ к указанному элементу
(открытая функция-член std::vector<T,Allocator>)
operator[]
доступ к указанному элементу или его вставка
(открытая функция-член std::map<Key,T,Compare,Allocator>)
operator[]
доступ к указанному элементу или его вставка
(открытая функция-член std::unordered_map<Key,T,Hash,KeyEqual,Allocator>)
operator[]
доступ к элементу по индексу
(открытая функция-член std::reverse_iterator<Iter>)
operator[]
доступ к элементу по индексу
(открытая функция-член std::move_iterator<Iter>)
operator[]
получение/задание элемента, среза или маски valarray
(открытая функция-член std::valarray<T>)
operator[]
возвращает указанное подсовпадение
(открытая функция-член std::match_results<BidirIt,Alloc>)

Операторы разыменования и доступа к членам перегружены во многих классах итераторов и умных указателей:

operator*operator->
разыменовывает указатель на управляемый объект
(открытая функция-член std::unique_ptr<T,Deleter>)
operator*operator->
разыменовывает сохранённый указатель
(открытая функция-член std::shared_ptr<T>)
operator*operator->
обеспечивает доступ к управляемому объекту
(открытая функция-член std::auto_ptr<T>)
operator*
разыменовывает итератор
(открытая функция-член std::raw_storage_iterator<OutputIt,T>)
operator*operator->
разыменовывает уменьшенный базовый итератор
(открытая функция-член std::reverse_iterator<Iter>)
operator*
ничего не делает
(открытая функция-член std::back_insert_iterator<Container>)
operator*
ничего не делает
(открытая функция-член std::front_insert_iterator<Container>)
operator*
ничего не делает
(открытая функция-член std::insert_iterator<Container>)
operator*operator->
обеспечивает доступ к элементу, на который указывает итератор
(открытая функция-член std::move_iterator<Iter>)
operator*operator->
возвращает текущий элемент
(открытая функция-член std::istream_iterator<T,CharT,Traits,Distance>)
operator*
ничего не делает
(открытая функция-член std::ostream_iterator<T,CharT,Traits>)
operator*
получает копию текущего символа
(открытая функция-член std::istreambuf_iterator<CharT,Traits>)
operator*
ничего не делает
(открытая функция-член std::ostreambuf_iterator<CharT,Traits>)
operator*operator->
обеспечивает доступ к текущему совпадению
(открытая функция-член std::regex_iterator<BidirIt,CharT,Traits>)
operator*operator->
обеспечивает доступ к текущему подсовпадению
(открытая функция-член std::regex_token_iterator<BidirIt,CharT,Traits>)

Ни один класс стандартной библиотеки не перегружает operator&. Наиболее известный пример перегруженного operator& — класс Microsoft COM CComPtr, хотя этот оператор также встречается в EDSL, таких как boost.spirit.

Ни один класс стандартной библиотеки не перегружает operator->*. Предлагалось использовать его как часть интерфейса умного указателя; и действительно, эту роль он выполняет у акторов в boost.phoenix, однако чаще он встречается в EDSL, таких как cpp.react.

Примечания

Макрос проверки поддержки возможностей Значение Стандарт Возможность
__cpp_multidimensional_subscript 202110L (C++23) Многомерный оператор индексирования

Отчёты об ошибках

Следующие отчёты об ошибках, изменяющие поведение, были ретроактивно применены к ранее опубликованным стандартам C++.

DR Применён к Опубликованное поведение Корректное поведение
CWG 1213 C++11 индексирование rvalue-массива приводило к lvalue переклассифицировано как xvalue
CWG 1458 C++98 применение & к lvalue неполного типа класса, который
объявляет operator&, приводило к неопределённому поведению
не указано,
какой & используется
CWG 1642 C++98 правый операнд rhs  встроенных операторов доступа через указатель на член мог быть lvalue может быть только rvalue
CWG 1800 C++98 при применении & к нестатическому члену данных
анонимного объединения-члена было неясно,
учитывается ли анонимное объединение в типе результата
анонимное объединение
не включается в
тип результата
CWG 2614 C++98 результат E1.E2 был неясен, если E2 является членом-ссылкой или перечислителем прояснено
CWG 2725 C++98 если E2 является статической функцией-членом, E1.E2 корректно
даже если это не левый операнд operator()
E1.E2 некорректно
в этом случае
CWG 2748 C++98 поведение E1->E2 было неясным, если E1 является
нулевым указателем, а E2 ссылается на статический член
в этом случае
поведение не определено
CWG 2813 C++98 E1 не являлось выражением с отбрасываемым значением, если
E1.E2 обозначает статический член или перечисление
является
CWG 2823 C++98 поведение *expr было неясным, если expr
не указывает на объект или функцию
прояснено

См. также

Приоритет операторов

Перегрузка операторов

Основные операторы
Присваивание Инкремент,
декремент
Арифметические Логические Сравнение Доступ
к членам
Прочие
a = b
a += b
a -= b
a *= b
a /= b
a %= b
a &= b
a |= b
a ^= b
a <<= b
a >>= b
++a
--a
a++
a--
+a
-a
a + b
a - b
a * b
a / b
a % b
~a
a & b
a | b
a ^ b
a << b
a >> b
!a
a && b
a || b
a == b
a != b
a < b
a > b
a <= b
a >= b
a <=> b
a[...]
*a
&a
a->b
a.b
a->*b
a.*b
вызов функции

a(...)
запятая

a, b
условный оператор

a ? b : c
Специальные операторы

static_cast преобразует тип в другой связанный тип
dynamic_cast выполняет преобразование в иерархиях наследования
const_cast добавляет или удаляет cv-квалификаторы
reinterpret_cast преобразует тип в несвязанный тип
Приведение в стиле C преобразует тип в другой с помощью комбинации static_cast, const_cast и reinterpret_cast
new создаёт объекты с динамической длительностью хранения
delete уничтожает объекты, ранее созданные выражением new, и освобождает выделенную область памяти
sizeof определяет размер типа
sizeof... определяет размер пакета (начиная с C++11)
typeid получает информацию о типе
noexcept проверяет, может ли выражение выбросить исключение (начиная с C++11)
alignof определяет требования к выравниванию типа (начиная с C++11)
^^ создаёт значение отражения на основе грамматической конструкции (начиная с C++26)

Документация по C для Операторы доступа к членам

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/operator_member_access

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API