Const reference as a member of a class insconsistency - c++

If one creates a const reference to a temporary, its life is extended as if the reference where in the stack.
It is a good feature of the language, although it is presented sometimes like an exception to other rules.
https://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/
However this doesn't work when the const reference is part the member of a class.
Is this an inconsistency of the language?
Example code:
int f(int a){return a + 5;}
int main(){
int const& b = f(2);
assert(b == 7); // ok, not a dangling reference
struct single{
int const& m_;
single(int const& m) : m_(m){}
};
single s{f(3)};
assert(s.m_ == 8); // fails, dangling reference
struct pair{
int const& m1_;
int const& m2_;
pair(int const& m1, int const& m2) : m1_(m1), m2_(m2){}
};
pair p{f(3), f(4)};
assert( p.m1_ == 8 ); // fails, dangling reference
}
Is there a workaround for this to work or at least behave more consistently?
I found this to be a limiting factor in a few contexts now. For example, List using with references, changes behavior when used as a member and https://stackoverflow.com/a/51878764/225186
EDIT1: In other answers to similar questions is mentioned that the problem is that the constructor takes a const& where the rule doesn't apply.
However a perfect forward still fails.
In this case, either the inconsistency in the language is more evident or perfect forward is not as perfect.
struct single{
int const& m_;
template<class T>
single(T&& m) : m_(std::forward<T>(m)){}
};
EDIT2: Declaring single const& s{f(3)}; still doesn't help.
However "moving" the constness to the structure helps.
struct single{
int m_; // no const!
template<class T>
single(T&& m) : m_(std::forward<T>(m)){}
};
...
single const& s{f(3)}; // const ref with extended lifetime
So, perhaps it is good practice to transfer the constness to the whole struct.
I still think that reference members behave weirdly in the language. https://www.youtube.com/watch?v=uYDt1gCDxhM
EDIT3: As #Oliv mentions, the situation improves if one uses agregate initialization. However this is quite limiting.
struct single{
int const& m_;
};
...
single s{f(3)};
assert(s.m_ == 5);

Related

Using mutable to allow modification of object in unordered_set

Please consider the following code:
#include <iostream>
#include <unordered_set>
struct MyStruct
{
int x, y;
double mutable z;
MyStruct(int x, int y)
: x{ x }, y{ y }, z{ 0.0 }
{
}
};
struct MyStructHash
{
inline size_t operator()(MyStruct const &s) const
{
size_t ret = s.x;
ret *= 2654435761U;
return ret ^ s.y;
}
};
struct MyStructEqual
{
inline bool operator()(MyStruct const &s1, MyStruct const &s2) const
{
return s1.x == s2.x && s1.y == s2.y;
}
};
int main()
{
std::unordered_set<MyStruct, MyStructHash, MyStructEqual> set;
auto pair = set.emplace(100, 200);
if (pair.second)
pair.first->z = 300.0;
std::cout << set.begin()->z;
}
I am using mutable to allow modification of the member z of MyStruct. I would like to know if this is ok and legal, since the set is a) unordered and b) I am not using z for hashing or equality?
I would say this is a perfect use of the "Mutable" keyword.
The mutable keyword is there to mark members that are not part of the "state" of the class (ie they are some form of cached or intermediate value that does not represent the logical state of the object).
Your equality operator (as well as other comparators (or any function that serializes the data) (or function that generates a hash)) define the state of the object. Your equality comparitor does not use the member 'z' when it checks the logical state of the object so the member 'z' is not part of the state of the class and is therefore illegable to use the "mutable" accessor.
Now saying that. I do think the code is very brittle to write this way. There is nothing in the class that stops a future maintainer accidentally making z part of the state of the class (ie adding it to the hash function) and thus breaking the pre-conditions of using it in std::unordered_set<>. So you should be very judicious in using this and spend a lot of time writing comments and unit tests to make sure the preconditions are maintained.
I would also look into "#Andriy Tylychko" comment about breaking the class into a const part and a value part so that you could potentially use it as part of a std::unordered_map.
The problem is that z is not part of the state of the object only in the context of that particular kind of unordered_set.
If one continues this route one will end up making everything mutable just in case.
In general, what you are asking is not possible because the element hash would need to be recomputed automatically on the modification of the element.
The most general thing you can do is to have a protocol for element modification, similar to the modify function in Boost.MultiIndex https://www.boost.org/doc/libs/1_68_0/libs/multi_index/doc/reference/ord_indices.html#modify.
The code is ugly, but thanks to the existence of extract it can be made fairly efficient when it matters (well, still your particular struct will not benefit from move).
template<class UnorderedSet, class It, class F>
void modify(UnorderedSet& s, It it, F f){
It h = it; ++h;
auto val = std::move(s.extract(it).value());
f(val);
s.emplace_hint(h, std::move(val) );
}
int main(){
std::unordered_set<MyStruct, MyStructHash, MyStructEqual> set;
auto pair = set.emplace(100, 200);
if (pair.second) modify(set, pair.first, [](auto&& e){e.z = 300;});
std::cout << set.begin()->z;
}
(code not tested)
#JoaquinMLopezMuños (author of Boost.MultiIndex) suggested reinserting the whole node. I think that would work like this:
template<class UnorderedSet, class It, class F>
void modify(UnorderedSet& s, It it, F f){
It h = it; ++h;
auto node = s.extract(it);
f(node.value());
s.insert(h, std::move(node));
}
EDIT2: Final tested code, needs C++17 (for extract)
#include <iostream>
#include <unordered_set>
struct MyStruct
{
int x, y;
double z;
MyStruct(int x, int y)
: x{ x }, y{ y }, z{ 0.0 }
{
}
};
struct MyStructHash
{
inline size_t operator()(MyStruct const &s) const
{
size_t ret = s.x;
ret *= 2654435761U;
return ret ^ s.y;
}
};
struct MyStructEqual
{
inline bool operator()(MyStruct const &s1, MyStruct const &s2) const
{
return s1.x == s2.x && s1.y == s2.y;
}
};
template<class UnorderedSet, class It, class F>
void modify(UnorderedSet& s, It it, F f){
auto node = s.extract(it++);
f(node.value());
s.insert(it, std::move(node));
}
int main(){
std::unordered_set<MyStruct, MyStructHash, MyStructEqual> set;
auto pair = set.emplace(100, 200);
if(pair.second) modify(set, pair.first, [](auto&& e){e.z = 300;});
std::cout << set.begin()->z;
}
The typical used mutable is to allow a const method to change a data member that does not form part of an object’s fundamental state e.g. a lazily evaluated value derived from the object’s non-mutable data.
Declaring public data members mutable is not good a practice, you are allowing the objects state to be changed externally even when that object is marked const.
In your example code, you have used mutable because (based on your comment), your code would not compile without it. Your code would not compile because the iterator returned from emplace is const.
There are two incorrect ways to solve this problem, one is the use of the mutable keyword, another, almost as bad, is to cast the const reference into a non-const reference.
The emplace method is intended to construct an object directly into the collection and avoid a copy constructor call. This is a useful optimization but you shouldn’t use it if it will compromise the maintainability of your code. You should either initialize z in your constructor or you should not use emplace to add the object to the set, instead set the value of z and then insert the object into your set.
If your object never needs to change after construction, you should make your class/struct immutable by either declaring them const or declaring the data members private and adding non-mutating accessor methods (these should be declared const).

How to combine lazy evaluation with auto in C++

Some background on what I try to do:
I am trying to implement a library doing quantum mechanics. As quantum mechanics is basically just linear algebra, I'm using the armadillo linear algebra library underneath. Armadillo uses lazy evaluation to do some smart tricks with matrices, which gives a pretty good abstraction from what is actually going on and looks close to matlab code.
I want to do something similar, but I also want to be able to use auto, which is not possible with armadillo (or eigen).
I have been looking around a little, and this answer contains what I think is the typical way of implementing this: https://stackoverflow.com/a/414260/6306265
The problem with this approach is that when you write
auto C = A+B;
you get a C that is a matrix_add, not a matrix. Even if matrix_add behaves similarly enough to matrix, the fact that matrix_add contains references to A and B makes it awkward to carry around. E.g.
auto A = matrix(2,2,{0,1,0,1});
auto B = matrix(2,2,{1,0,1,0});
auto C = A+B;
C.printmatrix(); // 1,1 ; 1,1
but
auto A = matrix(2,2,{0,1,0,1});
auto B = matrix(2,2,{1,0,1,0});
auto C = A+B;
A(0,0) = 1;
C.printmatrix(); // 2,1 ; 1,1
which is counter-intuitive. As mathematically intuitive behaviour is what I want to achieve, that is a problem.
Even worse is when I do
auto sumMatrices(const matrix& A, const matrix& B)
{
return A+B;
}
which returns a matrix_add with references to local memory.
I would really like to be able to have the nice, overloaded behaviour but also be able to use auto. My idea was to make a wrapper that can hold either a reference or an instance:
template<class T>
class maybe_reference
{
public:
maybe_reference(const T& t):
ptr_(std::make_unique<T>(t)),
t_(*ptr_)
{}
maybe_reference(std::reference_wrapper<const T> t):
t_(t.get())
{}
const T& get(){return t_;}
private:
unique_ptr<T> ptr_;
const T& t_;
}
It may not be implemented exactly this way, but the general idea is to have two constructors that can be clearly distinguished to ensure that get() returns either the referenced object or the one in the unique_ptr.
Modified matrix_add:
class matrix_add {
public:
friend matrix_add operator+(const matrix& A, const matrix& B);
matrix_add(matrix_add&& other): A_(other.A_.get()), B_(other.B_.get()){}
private:
matrix_add(const matrix& A, const matrix& B): A_(std::ref(A)), B_(std::ref(B)){}
maybe_reference<matrix> A_;
maybe_reference<matrix> B_;
};
I have left out all the parts that make matrix_add behave like a matrix. The idea is to have the object refer to the outside objects A&B as long as it was constructed with A+B, but when it is move-constructed, it would own copies.
My question is basically: does this work?
I have been thinking that the move-constructor may be elided in some or all cases, which might be devastating.
Also, is there an alternative to achieve the same thing? I have been looking, but it seems that for linear algebra at least its either lazy or auto.
EDIT: Thanks to being reminded of the term "expression templates", my google search was a lot more fruitful. I found this reddit-post: https://www.reddit.com/r/cpp/comments/4puabu/news_about_operator_auto/
and the referenced papers, which allow specification of "casts" to auto. That would be the feature that really would make all of this work.
I think, your basic problem is, that lazy evaluation does not mix well with changing state. I see two possible routes out of this:
Make your matrices immutable. If you "modify" a matrix, you actually create a copy with the incorporated change, the original remains intact. This works well semantically (any math works exactly as you expect it to do), however it may incur an intolerable runtime overhead if you are setting your matrices value by value.
This allows your implementation of matrix_add to silently replace itself with a matrix object when it is evaluated, ensuring that each evaluation is only performed at most once.
Make your functions explicit. Don't create matrix_add objects that act as if they were matrices themselves, but create matrix_function objects that operate on some input matrices to yield some result. This allows you to explicitly perform the evaluation where you see fit, and to reuse the functions that you define. However, this approach will lead to a lot of additional code complexity.
I don't think it's a good idea to try to work around this problem by introducing implicit points of forced evaluation: You'll loose large parts of what can be achieved by lazy evaluation, so why bother in the first place? Just my two cents.
You could write a template function evaluate which by default is a NOP, and then overload as necessary.
#include <utility>
#include <type_traits>
struct matrix {};
struct matrix_add {
matrix operator()() const;
};
matrix_add operator + (matrix const& a, matrix const& b);
template<class T> decltype(auto) evaluate(T&& val) { return std::forward<T>(val); }
matrix evaluate(matrix_add const& lazy) { return lazy(); }
matrix evaluate(matrix_add & lazy) { return lazy(); }
matrix evaluate(matrix_add && lazy) { return lazy(); }
int main()
{
auto a = matrix();
auto b = matrix();
auto c = evaluate(a + b);
auto d = evaluate(1 + 2);
static_assert(std::is_same<decltype(c), matrix>::value, "");
static_assert(std::is_same<decltype(d), int>::value, "");
}
I will define a new operator: eager_eval, like this:
namespace lazy {
template<class T>
void eager_eval(T const volatile&)=delete;
template<class T>
struct expression {
template<class D,
std::enable_if_t<std::is_base_of<expression, std::decay_t<D>>{}, int> =0
>
friend T eager_eval( D&& d ) { return std::forward<D>(d); }
};
}
Whenever you want something to be evaluatable in an eager manner, define eager_eval in its namespace, or derive it from lazy::lazy_expression<target_type>.
So we modify your matrix_add to (A) derive from it with the lazy-produced type you want, and (B) have an operator matrix:
struct matrix_add:
lazy::expression<matrix>
{
matrix_add(matrix const& a, matrix const& b) : a(a), b(b) { }
operator matrix() && { // rvalue ref qualified as it should be.
matrix result;
// Do the addition.
return result;
}
private:
matrix const& a, b;
};
and now, anyone can do:
auto e = eager_eval( a+b );
and ADL finds the right type to eager evaluate the lazy expression to.
live example.
You could, optionally, implement a default eager_eval that returns its argument:
template<class T, class...Ts>
T eager_eval(T&& t, Ts&&...) { return std::forward<T>(t); }
then
using lazy::eager_eval;
auto x = eager_eval( 1+2 );
lets you be agnostic to the type you pass to eager_eval; if it is a type that is aware of being lazy via an eager_eval overload, it converts, and if not it does not convert.
The pack in lazy::eager_eval above is to ensure that it has the lowest priority as an overload.
with c++17 class template argument deduction, you may write
struct matrix_expr_foo {};
struct matrix_expr_bar {};
template< typename L, typename R >
struct matrix_add {
// ...
};
matrix_add<matrix_expr_foo,matrix_expr_bar> operator + (matrix_expr_foo const& a, matrix_expr_bar const& b);
template< typename T >
struct expr {
expr( T const& expr ){
// evaluate expr ( to be stored in an appropriate member )
}
// ...
};
int main()
{
auto a = matrix_expr_foo();
auto b = matrix_expr_bar();
expr c = a + b;
/* different naming ?
auto_ c = a + b;
...
*/
}
where expr is meant to act as an auto for expression templates ...

Is there any way to call class operators with out using * , in a pointer to class type?

Is it possible to call operator[] with out using * when I have a pointer to the class ?
class MyClass
{
public:
void operator[](int n)
{
cout<<"In []";
}
};
int main()
{
MyClass *a=new MyClass;
(*a)[2];//work
a[2];//It just do some pointer arithmetic ...too bad :((
}
Yes, you should be able to use the -> operator, like this:
a->operator[] (2);
Demo on ideone.
If all you need is eliminating the asterisk, this should do the trick. If you are aiming for a better readability, this isn't of much help - you need to either avoid the pointer, or to use a regular member function:
class MyClass
{
public:
void operator[](int n)
{
cout<<"In []";
}
// Add a regular function for use with pointers
// that forwards the call to the operator[]
void at(int n) { (*this)[n]; }
};
Now you can write a->at(2);
(Demo on ideone).
template<typename LHS> struct at_lhs_t { LHS lhs; };
static struct at_t {} at;
template<typename LHS>
at_lhs_t<LHS> operator%( LHS&& lhs, at_t )
{ return {std::forward<LHS>(lhs)}; }
template<typename LHS, typename RHS>
auto operator%( at_lhs_t<LHS>&& lhs, RHS&& rhs )
->decltype( (std::forward<LHS>(lhs.lhs))->operator[](std::forward<RHS>(rhs)) )
{ return ( (std::forward<LHS>(lhs.lhs))->operator[](std::forward<RHS>(rhs)) ); }
class MyClass
{
public:
void operator[](int n)
{
std::cout<<"In []";
}
};
int main()
{
MyClass *a=new MyClass;
a %at% 2;
}
live example, but this is probably not what you want either.
In practice, just use the *. The * (as well as ->s) help remind you that the left hand side must be first checked for validity before it can be used in most contexts. After you check that your pointer is valid, you can dereference and store it in a reference for the duration of the current scope, and use [] to your heart's content.
The (*a) brackets get to be a bit annoying. On the other hand, possibly you should also avoid using pointers as much: modern C++ has moved away from using pointers, and would rather wrap things in smart pointers or pImpl wrappers and store the data in value-semantic types.
Then you only deal with pointers inside your smart pointer storage types, and when you want reseatable indirection to resources held elsewhere. Your nice and pretty pImpl wrappers are used more often, and they act like values even if most of their state is held dynamically.

Compile-Time Named Parameter Idiom with constexpr

I've recently run into a quite a few situations where the Named Parameter Idiom would be useful, but I'd like it to be guaranteed in compile-time. The standard method of returning references in a chain almost always appears to invoke a run-time constructor (compiling with Clang 3.3 -O3).
I haven't been able to find anything with reference to this so I tried to get this to work with constexpr and got something functional:
class Foo
{
private:
int _a;
int _b;
public:
constexpr Foo()
: _a(0), _b(0)
{}
constexpr Foo(int a, int b)
: _a(a), _b(b)
{}
constexpr Foo(const Foo & other)
: _a(other._a), _b(other._b)
{}
constexpr Foo SetA(const int a) { return Foo(a, _b); }
constexpr Foo SetB(const int b) { return Foo(_a, b); }
};
...
Foo someInstance = Foo().SetB(5).SetA(2); //works
While this is okay for a small number of parameters, for larger numbers it quickly blows up into a mess:
//Unlike Foo, Bar takes 4 parameters...
constexpr Bar SetA(const int a) { return Bar(a, _b, _c, _d); }
constexpr Bar SetB(const int b) { return Bar(_a, b, _c, _d); }
constexpr Bar SetC(const int c) { return Bar(_a, _b, c, _d); }
constexpr Bar SetD(const int d) { return Bar(_a, _b, _c, d); }
Is there a better way? I'm looking at doing this with classes that have many (30+) parameters and this seems like it would be prone to error if extended in the future.
EDIT: Removed C++1y tag -- while C++1y does appear to fix the problem (thanks TemplateRex!) this is for production code, and we are stuck with C++11. If that means its impossible, then I guess that's just the way it is.
EDIT2: To show why I'm looking for this, here's a use case. Currently with our platform, developers need to explicitly set bit vectors for hardware configurations, and while this is okay it's very error prone. Some are using designated initializers from the C99 extension, which is okay but non-standard:
HardwareConfiguration hardwareConfig = {
.portA = HardwareConfiguration::Default,
.portB = 0x55,
...
};
Most, however, aren't even using this, and are just inputting a blob of numbers. So as a working improvement, I'd like to move towards something like this (since it also forces better code):
HardwareConfiguration hardwareConfig = HardwareConfiguration()
.SetPortA( Port().SetPolarity(Polarity::ActiveHigh) )
.SetPortB( Port().SetPolarity(Polarity::ActiveLow) );
Which might be far more verbose, but much clearer when reading later.
Using Template Metaprogramming
Here is something I came up with to solve your problem (at least partially). By using template metaprogramming, you can leverage the compiler to do most of the job for you. These techniques look weird for those who have never seen such code before, but thankfully most of the complexity can be hidden away in a header and the users only interact with the library in a neat and terse manner.
A Sample Class Definition and its Use
Here is an example of what defining a class would entail on your part:
template <
//Declare your fields here, with types and default values
typename PortNumber = field<int, 100>,
typename PortLetter = field<char, 'A'>
>
struct MyStruct : public const_obj<MyStruct, PortNumber, PortLetter> //Derive from const_obj like this, passing the name of your class + all field names as parameters
{
//Your setters have to be declared like this, by calling the Set<> template provided by the base class
//The compiler needs to be told that Set is part of MyStruct, probably because const_obj has not been instantiated at this point
//in the parsing so it doesn't know what members it has. The result is that you have to use the weird 'typename MyStruct::template Set<>' syntax
//You need to provide the 0-based index of the field that holds the corresponding value
template<int portNumber>
using SetPortNumber = typename MyStruct::template Set<0, portNumber>;
template<int portLetter>
using SetPortLetter = typename MyStruct::template Set<1, portLetter>;
template<int portNumber, char portLetter>
using SetPort = typename MyStruct::template Set<0, portNumber>
::MyStruct::template Set<1, portLetter>;
//You getters, if you want them, can be declared like this
constexpr int GetPortNumber() const
{
return MyStruct::template Get<0>();
}
constexpr char GetPortLetter() const
{
return MyStruct::template Get<1>();
}
};
Using the Class
int main()
{
//Compile-time generation of the type
constexpr auto myObject =
MyStruct<>
::SetPortNumber<150>
::SetPortLetter<'Z'>();
cout << myObject.GetPortNumber() << endl;
cout << myObject.GetPortLetter() << endl;
}
Most of the job is done by the const_obj template. It provides a mechanism to modify your object at compile time. Much like a Tuple, the fields are accessed with 0-based indices but this does not stop you from wrapping the setters with friendly names, as is done with SetPortNumber and SetPortLetter above. (They just forward to Set<0> and Set<1>)
About Storage
In the current implementation, after all the setters have been called and the object declared, the fields end up being stored in a compact array of const unsigned char's named data in the base class. If you use fields that are not unsigned chars (as in done above with PortNumber for example) the field is divided in big endien unsigned char's (could be changed to little endien as needed). If you don't need an actual storage that has an actual memory address, you could omit it altogether by modifying the packed_storage (see full implementation link below) and the values would still be accessible at compile time.
Limitations
This implementation only allows integral types to be used as fields (all flavors of shorts, ints, longs, bool, char). You can still provide setters that act on more than one field though. Example:
template<int portNumber, char portLetter>
using SetPort = typename MyStruct::template Set<0, portNumber>::
MyStruct::template Set<1, portLetter>;
Full Code
The full code for the implementation of this little library can be found here:
Full Implementation
Additional Notes
This code has been tested and works with the C++11 implementation of both g++ and clang.
It has not been tested for hours and hours so of course there may be bugs but it should provide you with a good base to start with. I hope this helps!
In C++14, constraints on constexpr function will be relaxed, and the usual chaining of reference-returning setters will work at compile-time:
#include <iostream>
#include <iterator>
#include <array>
#include <utility>
class Foo
{
private:
int a_ = 0;
int b_ = 0;
int c_ = 0;
int d_ = 0;
public:
constexpr Foo() = default;
constexpr Foo(int a, int b, int c, int d)
:
a_{a}, b_{b}, c_{c}, d_{d}
{}
constexpr Foo& SetA(int i) { a_ = i; return *this; }
constexpr Foo& SetB(int i) { b_ = i; return *this; }
constexpr Foo& SetC(int i) { c_ = i; return *this; }
constexpr Foo& SetD(int i) { d_ = i; return *this; }
friend std::ostream& operator<<(std::ostream& os, const Foo& f)
{
return os << f.a_ << " " << f.b_ << " " << f.c_ << " " << f.d_ << " ";
}
};
int main()
{
constexpr Foo f = Foo{}.SetB(5).SetA(2);
std::cout << f;
}
Live Example using Clang 3.4 SVN trunk with std=c++1y.
I'm not sure if classes with 30 parameters are a good idea (Single Responsiblity Principle and all that) but at least the above code scales linearly in the number of setters, with only 1 argument per setter. Note also that there are only 2 constructors: the default one (which takes its arguments from the in-class initializers) and the full one which takes 30 ints in your ultimate case).

vector and const

Consider this
void f(vector<const T*>& p)
{
}
int main()
{
vector<T*> nonConstVec;
f(nonConstVec);
}
The following does not compile.The thing is that vector<T*> can not be converted to vector <const T*> , and that seems illogically to me , because there exists implicit conversion from T* to const T*. Why is this ?
vector<const T*> can not be converted to vector <T*> too, but that is expected because const T* can not be converted implicitly to T*.
I've added a few lines to your code. That's sufficient to make it clear why this is disallowed:
void f(vector<const T*>& p)
{
static const T ct;
p.push_back(&ct); // adds a const T* to nonConstVec !
}
int main()
{
vector<T*> nonConstVec;
f(nonConstVec);
nonConstVec.back()->nonConstFunction();
}
vector<T> and vector<const T> are unrelated types. The fact that T can be converted to const T doesn't mean a thing here.
You have to think about it from a type system's standpoint. Instantiated vector<int> doesn't have anything in common with vector<const int>.
It may be worth showing why it's a breach of const-correctness to perform the conversion you want:
#include <vector>
const int a = 1;
void addConst(std::vector<const int *> &v) {
v.push_back(&a); // this is OK, adding a const int* to a vector of same
}
int main() {
std::vector<int *> w;
int b = 2;
w.push_back(&b); // this is OK, adding an int* to a vector of same
*(w.back()) = 3; // this is OK, assigning through an int*
addConst(w); // you want this to be OK, but it isn't...
*(w.back()) = 3; // ...because it would make this const-unsafe.
}
The problem is that vector<int*>.push_back takes a pointer-to-non-const (which I'll call a "non-const pointer" from now on). That means, it might modify the pointee of its parameter. Specifically in the case of vector, it might hand the pointer back out to someone else who modifies it. So you can't pass a const pointer to the push_back function of w, and the conversion you want is unsafe even if the template system supported it (which it doesn't). The purpose of const-safety is to stop you passing a const pointer to a function which takes a non-const pointer, and this is how it does its job. C++ requires you to specifically say if you want to do something unsafe, so the conversion certainly can't be implicit. In fact, because of how templates work, it's not possible at all (see later).
I think C++ could in principle preserve const-safety by allowing a conversion from vector<T*>& to const vector<const T*>&, just as int ** to const int *const * is safe. But that's because of the way vector is defined: it wouldn't necessarily be const-safe for other templates.
Likewise, it could in theory allow an explicit conversion. And in fact, it does allow an explicit conversion, but only for objects, not references ;-)
std::vector<const int*> x(w.begin(), w.end()); // conversion
The reason it can't do it for references is because the template system can't support it. Another example that would be broken if the conversion were allowed:
template<typename T>
struct Foo {
void Bar(T &);
};
template<>
struct Foo<const int *> {
void Baz(int *);
};
Now, Foo<int*> doesn't have a Baz function. How on earth could a pointer or reference to Foo<int*> be converted to a pointer or reference to Foo<const int*>?
Foo<int *> f;
Foo<const int *> &g = f; // Not allowed, but suppose it was
int a;
g.Baz(&a); // Um. What happens? Calls Baz on the object f?
Think of like this:
You have two class like this:
class V { T* t;};
class VC { T const* t;};
Do you expect these two classes to be convertible automatically?
This is basically what a template class is. Each variation is a completely new type.
Thus vector<T*> and vector<T const*> are completely different types.
My first question is do you really want to store pointers?
If yes, I would suggest looking at boost::ptr_container. This holds pointers and deletes them when the vector is destroyed. But more importantly it treats the contained pointers as a normal std:vector treats its contained objects. Thus by making the vector const you can only access its members as const
void function(boost::ptr_vector<T> const& x)
{
x.push_back(new T); // Fail x is const.
x[4].plop(); // Will only work if plop() is a const member method.
}
If you don't need to store pointers then store the objects (not the pointers) in the container.
void function(std::vector<T> const& x)
{
x.push_back(T()); // Fail x is const.
x[4].plop(); // Will only work if plop() is a const member method.
}
Others have already given the reason why the code you gave doesn't compile, but I have a different answer on how to deal with it. I don't believe there's any way to teach the compiler how to automatically convert the two (because that would involve changing the definition of std::vector). The only way around this annoyance is to do an explicit conversion.
Converting to a completely different vector is unsatisfying (wastes memory and cycles for something that should be completely identical). I suggest the following:
#include <vector>
#include <iostream>
using namespace std;
typedef int T;
T a = 1;
T b = 2;
void f(vector<const T*>& p)
{
for (vector<const T*>::const_iterator iter = p.begin(); iter != p.end(); ++iter) {
cout << **iter << endl;
}
}
vector<const T*>& constify(vector<T*>& v)
{
// Compiler doesn't know how to automatically convert
// std::vector<T*> to std::vector<T const*> because the way
// the template system works means that in theory the two may
// be specialised differently. This is an explicit conversion.
return reinterpret_cast<vector<const T*>&>(v);
}
int main()
{
vector<T*> nonConstVec;
nonConstVec.push_back(&a);
nonConstVec.push_back(&b);
f(constify(nonConstVec));
}
I'm using reinterpret_cast to declare that the two things are the same. You SHOULD feel dirty after using it, but if you put it in a function by itself with a comment for those following you, then have a wash and try to continue on your way with a good conscience, though you will always (rightly) have that nagging worry about someone pulling the ground out from under you.
As others have said, conversions aren't applied to the template parameters. Put another way,
vector<T>
...and:
vector<const T>
... are completely different types.
If you are trying to implement const-correctness in regard to f() not modifying the contents of the vector, this might be more along the lines of what you're looking for:
void f(vector<T>::const_iterator begin, vector<T>::const_iterator end)
{
for( ; begin != end; ++begin )
{
// do something with *begin
}
}
int main()
{
vector<T> nonConstVec;
f(nonConstVec.begin(), nonConstVec.end());
}
in addition to other answers, it's worth reading C++ FQA Lite where this (and many others C++ features) are discussed from a critical POV:
http://yosefk.com/c++fqa/const.html#fqa-18.1
That's the way templates work - no conversions are applied on the template parameters, so the two vectors are of completely different types.
Both vector<const T*> and vector<T*> are completely different types. Even if you write const T* inside your main(), your code wont compile. You need to provide specialization inside main.
The following compiles:
#include<vector>
using namespace std;
template<typename T>
void f(vector<const T*>& p)
{
}
int main()
{
vector<const int*> nonConstVec;
f(nonConstVec);
}
Templates are a bit strange that way. The fact that there's an implicit conversion from T to U doesn't mean that there's an implicit conversion from XXX to XXX. It can be made to happen, but it takes a fair amount of extra work in the template code to make it happen, and offhand, I doubt the techniques were all known when std::vector was being designed (more accurately, I'm pretty sure they weren't known).
Edit: Issues like this are part of the motivation behind using iterators. Even though a container of X isn't implicitly convertible to a container of const X, a container<X>::iterator is implicitly convertible to a container<X>::const_iterator.
If you replace your:
void f(vector<const T*>& p) {}
with:
template <class const_iter>
void f(const_iter b, const_iter e) {}
Then:
int main() {
vector<T*> nonConstVec;
f(nonConstVec.begin(), nonConstVec.end());
return 0;
}
will be just fine -- and so will:
vector<T const *> constVec;
f(constVec.begin(), constVec.end());