Reputation: 171
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;
};
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
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
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