Учитывая контейнер, такой как 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)
}
@ FrançoisAndrieux извините, я имел в виду последний пример
Как будет работать auto в параметре функции A::h? Для меня он не компилируется в clang с C++ 17.
Ваш последний пример будет работать нормально, если вы переместите x так, чтобы он был объявлен до, он использовался в decltype(x).
decltype() - это не обходной путь, а способ сделать это, и он работает в классах, вам просто нужно определить эту переменную, прежде чем использовать ее.
return *it + *(++it); отличный пример с UB :)
@Slava Я был удивлен, что не получил предупреждений о точках последовательности ни с помощью clang, ни с gcc. Неужели итераторы для этого слишком сложны?
@Slava благодарит за указание на это, хотя это может быть не указано, а не undefined, так как C++ 17, поскольку порядок оценки для аргументов функции не указан.
Как это связано с порядком вычисления аргументов функции?
Я отказываюсь от своего утверждения, это, вероятно, UB. Уберу это из вопроса :)
Если вы просто измените порядок в своем классе, на class A { private: vector<int> x; public: int h(decltype(x)::iterator it) { return *it + *(++it); } }; он будет работать нормально. Переменная определяется перед использованием. Но забавные вещи случаются, когда конфликт имен class A { class B { }; int B; };
auto iter = v.begin();




По сути, C++ позволяет вам получать значения или типы при доступе к ним через ::. Так что MyType::AnotherType подойдет не хуже, чем MyType::AValue. Когда вы просматриваете экземпляр с ., это означает только то, что он хочет разрешить символ, который является своего рода значением (поле, функция и т. д.). Надеюсь, это поможет.
Вопрос не в какие C++, а в Почему.
Как отметил @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, объявленные в классе как члены, называются «вложенными типами» или «вложенными классами».
Член типа является член.
Интересный пример, но как ни странно он не компилируется в clang: godbolt.org/z/HTZ3Bg
! И работает в gcc. Я чувствовал, что эта программа недействителен, но не мог понять почему. Вот почему.
Существующие типы и объекты представляют собой параллельные юниверсы в C++ (один в основном во время компиляции, другой в основном во время выполнения). Точка применяется к объектам и, таким образом, должна работать во время выполнения и, следовательно, не для типов. В качестве примечания, вы можете использовать здесь
auto, чтобы сэкономить время на вводе текста.