the question is pretty simple, is it in general safe a static cast (or some other cast) from
std::vector< Foo >
to
std::
Ignoring that you said std::vector for the moment and pretending you had some other less well defined vector implementation. Your code would be technically unsafe not because T
and T const
are quite different but because the C++ language permits vector
and vector
to be specialised in ways that are quite different. Consider the following code:
#include
template
struct vector {
T* start_;
T* end_;
T* cap_end_;
};
template
struct vector {
bool gotcha_;
T* start_;
T* end_;
T* cap_end_;
};
struct foo { };
int
main()
{
std::cout
<< sizeof(vector) << '\n'
<< sizeof(vector) << '\n'
;
}
Note that there are other more pernicious changes that could make your life miserable. Such as the following where the members are reordered:
#include
template
struct vector {
T* start_;
T* end_;
T* cap_end_;
};
template
struct vector {
T* end_;
T* cap_end_;
T* start_;
};
template
long size(vector const& v)
{
return v.end_ - v.start_;
}
struct foo { };
int
main()
{
vector v;
v.start_ = new foo[10];
v.end_ = v.start_ + 1;
v.cap_end_ = v.start_ + 10;
std::cout
<< size(v) << '\n'
<< size(*reinterpret_cast*>(&v)) << '\n'
;
return 0;
}
Wrt to std::vector, I am not familiar enough with the fine details of the standard library specification to know whether such specialisations would be conformant or not. Perhaps someone more well versed in the standard can comment.
Note some of what I said in answer to Casting templated class to more general specialization may help explain this problem.
To address your question about detecting specialisations there are ways to make your code unsafe by using no specialisations of the class but overloaded non-member functions and I am o not sure how you would detect that. Such as in the following:
#include
template
struct vector {
T* start_;
T* end_;
T* cap_end_;
};
template
void init(vector& v, size_t sz, size_t cap)
{
v.start_ = new T[cap];
v.end_ = v.start_ + sz;
v.cap_end_ = v.start_ + cap;
}
template
void init(vector& v, size_t sz, size_t cap)
{
v.end_ = new T const[cap];
v.cap_end_ = v.end_ + sz;
v.start_ = v.end_ + cap;
}
template
long size(vector& v)
{
return v.end_ - v.start_;
}
template
long size(vector& v)
{
return v.cap_end_ - v.end_;
}
struct foo { };
int
main()
{
vector v;
init(v, 1, 10);
std::cout
<< size(v) << '\n'
<< size(*reinterpret_cast*>(&v)) << '\n'
;
}
Enough with the bad news. The good news is that if you want to take an existing object with a general interface and restrict or adjust what can be done with that object there is are some simple, safe and comprehensible ways of doing that. Take a look at std::stack http://www.sgi.com/tech/stl/stack.html or alternatively this answer https://stackoverflow.com/a/994925/453436 to What is Proxy Class in C++