Araeos
Araeos

Reputation: 171

Accessing type members in C++

Given an container such as a vector<int>

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

Why does it seem to be quite difficult to access the public type members such as iterator and const_iterator? As I understand it, these names are part of the class (not the object) and must be accessed via :: to specify the scope, but is there a reason to forbid v.const_iterator when v is known? Example:

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

A workaround would be using decltype as in:

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

But this approach does not even work in classes, as the following fails:

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

Edit

Just a little sidenote. As pointed out, the meaning of v.iterator would depend on the type of v at the point of usage (compile time) ignoring runtime polymorphism. But the same is true for static class members. Example:

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)
}

Upvotes: 1

Views: 2473

Answers (2)

KamilCuk
KamilCuk

Reputation: 141010

As @Slava pointed out in comments, decltype(x) is the way to do it:

#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;
    }
};

The member access . operator and scope resolution operator :: may not be overloaded. And as you might deduce from the names, . is used to access members, while :: is used to access scope.

#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;
}

Also, there are no "type members" in C++ (at least I couldn't find them in C++ standard). Classes and enumerations and typedefs declarations declared in a class as members are called "nested types" or "nested classes".

Upvotes: 2

mister why
mister why

Reputation: 1987

Basically, C++ lets you get either values or types when you access them through ::. So MyType::AnotherType is fine as well as MyType::AValue. When you go through an instance with ., it only means it want to resolve a symbol which is a kind of a value (field, func, etc.). Hope that helps.

Upvotes: 0

Related Questions