Доступ к членам типа в C++

Учитывая контейнер, такой как vector<int>

#include <vector>
using namespace std;
vector<int> v{1, 2, 3};

Почему кажется довольно трудным получить доступ к членам общедоступного типа, таким как iterator и const_iterator? Насколько я понимаю, эти имена являются частью класса (а не объекта) и должны быть доступны через ::, чтобы указать область действия, но есть ли причина запретить v.const_iterator, когда известен v? Пример:

int f(v.iterator it) {
    return *it;
}
// or
int g(v::iterator it) {
    return *it;
}

Обходной путь - использовать decltype, как в:

int h(decltype(v)::iterator it) {
    return *it;
}

Но этот подход не работает даже в классах, так как следующее не работает:

class A
{
public:
    int h(decltype(x)::iterator it) {
        return *it;
    }
private:
    vector<int> x;
};

Редактировать

Небольшое примечание. Как уже указывалось, значение v.iterator будет зависеть от типа v в момент использования (время компиляции), игнорируя полиморфизм времени выполнения. Но то же самое верно и для статических членов класса. Пример:

struct A
{
    static const int x = 1;
};
struct B : public A
{
    static const int x = 2;
};
void eval()
{
    B b;
    A& ar = b;
    b.x; // 2
    ar.x; // 1, even though ar refers to the same underlying object (by the base type)
}

Существующие типы и объекты представляют собой параллельные юниверсы в C++ (один в основном во время компиляции, другой в основном во время выполнения). Точка применяется к объектам и, таким образом, должна работать во время выполнения и, следовательно, не для типов. В качестве примечания, вы можете использовать здесь auto, чтобы сэкономить время на вводе текста.

bipll 25.10.2018 16:57

@ FrançoisAndrieux извините, я имел в виду последний пример

463035818_is_not_a_number 25.10.2018 17:02

Как будет работать auto в параметре функции A::h? Для меня он не компилируется в clang с C++ 17.

Araeos 25.10.2018 17:03

Ваш последний пример будет работать нормально, если вы переместите x так, чтобы он был объявлен до, он использовался в decltype(x).

François Andrieux 25.10.2018 17:03
decltype() - это не обходной путь, а способ сделать это, и он работает в классах, вам просто нужно определить эту переменную, прежде чем использовать ее.
Slava 25.10.2018 17:06
return *it + *(++it); отличный пример с UB :)
Slava 25.10.2018 17:11

@Slava Я был удивлен, что не получил предупреждений о точках последовательности ни с помощью clang, ни с gcc. Неужели итераторы для этого слишком сложны?

Max Langhof 25.10.2018 17:15

@Slava благодарит за указание на это, хотя это может быть не указано, а не undefined, так как C++ 17, поскольку порядок оценки для аргументов функции не указан.

Araeos 25.10.2018 17:24

Как это связано с порядком вычисления аргументов функции?

Slava 25.10.2018 17:34

Я отказываюсь от своего утверждения, это, вероятно, UB. Уберу это из вопроса :)

Araeos 25.10.2018 17:42

Если вы просто измените порядок в своем классе, на class A { private: vector<int> x; public: int h(decltype(x)::iterator it) { return *it + *(++it); } }; он будет работать нормально. Переменная определяется перед использованием. Но забавные вещи случаются, когда конфликт имен class A { class B { }; int B; };

KamilCuk 25.10.2018 17:48
auto iter = v.begin();
Алексей Неудачин 25.10.2018 18:27
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
12
1 260
2

Ответы 2

По сути, C++ позволяет вам получать значения или типы при доступе к ним через ::. Так что MyType::AnotherType подойдет не хуже, чем MyType::AValue. Когда вы просматриваете экземпляр с ., это означает только то, что он хочет разрешить символ, который является своего рода значением (поле, функция и т. д.). Надеюсь, это поможет.

Вопрос не в какие C++, а в Почему.

n. 1.8e9-where's-my-share m. 25.10.2018 18:18

Как отметил @Slava в комментариях, decltype(x) - это способ сделать это:

#include <vector>
using namespace std;
vector<int> v{1, 2, 3};
int f(decltype(v)::iterator it) {
    return *it;
}

int g(decltype(v)::iterator it) {
    return *it;
}

class A
{
private:
    vector<int> x;
public:
    int h(decltype(x)::iterator it) {
        return *it;
    }
};

Оператор доступа к члену . и оператор разрешения области действия :: не могут быть перегружены. И, как можно понять из названий, . используется для доступ к участникам, а :: используется для доступа к сфера.

#include <iostream>

struct B {
    class iterator { };

    // no need for typename, compiler knows that we mean typedef B::iterator, as he can only find it
    iterator iterator1;

    // member named the same as class, ops!
    int iterator;

    // we need to use typename here, B::iterator is resolved as member
    // iterator iteartor3;
    typename B::iterator iterator2;
};

int main() {
    B bobj;

    // we access the member iterator inside b
    bobj.iterator = 1;

    // we declare object of B::iterator type
    // we need to tell compiler that we want only types
    typename B::iterator iterator;

    // this will work too
    typename decltype(bobj)::iterator iterator2;

    // we declare a member pointer to the iterator member inside some B class
    // no typename, as I want pointer to member, not pointer to... type
    int B::* pointer = &B::iterator;

    // this is just a pointer to the iterator specifically in bobj class
    int * pointer2 = &bobj.iterator;

    // foo(bar) 
    bobj.*pointer = 1;

    // this will work as expected
    int decltype(bobj)::* pointer3 = &B::iterator;
}

Кроме того, в C++ нет «членов типа» (по крайней мере, я не смог найти их в стандарте C++). Классы, перечисления и объявления typedefs, объявленные в классе как члены, называются «вложенными типами» или «вложенными классами».

Член типа является член.

n. 1.8e9-where's-my-share m. 25.10.2018 18:18

Интересный пример, но как ни странно он не компилируется в clang: godbolt.org/z/HTZ3Bg

Araeos 25.10.2018 18:36

! И работает в gcc. Я чувствовал, что эта программа недействителен, но не мог понять почему. Вот почему.

KamilCuk 25.10.2018 18:41

Другие вопросы по теме