I'm new to using initializer lists and I'm wondering if they work similar to other stl containers. By that I mean do they copy values? What I'm trying to do is a simple min() function like this:
template <class T> T& minArgs(const std::initializer_list<T&>& Arguments)
{
const T* Smallest = Arguments.begin();
for (const T* I = begin(Arguments); I != end(Arguments); ++I)
{
if (*I < *Smallest) Smallest = I;
}
return *Smallest;
}
However when I call the function I get this from GCC:
error: 'const' qualifiers cannot be applied to 'int&'
I've been playing around with this and it seems initializer_lists may not do what I want; I want the function to except non-POD arguments as well. Would a va_list be a better alternative?
Thanks!
When I try it, I get these errors. Yet, when I get rid of your pointless use of references, it all works.
std::initializer_list stores values, not references. You should be taking a const std::initializer_list<T> &, not a const std::initializer_list<T&> &.
All I'm trying to do is write a function that takes any number of arguments, by reference, and returns a reference to the largest of them.
[...]
Is this possible with initializer_lists?
No. std::initializer_list is for values, not references. But I see no reason why you couldn't take the items by value instead of by reference. Or, more to the point, why don't you just use std::min, which can take an initializer list?
Related
I have a function with a template parameter T and would like to pass a value of type const T by reference.
The C++ compiler throws an error, (kind of) understandably so. Hence I was wondering if there exists a way to do this in a safe and concise way?
I created a very small example that reflects the issue I am having in my project.
(in my project the issue appears in a constant member function of some class, but from my experiments the issue should be "faithfully" reflected in the example below by use of a constant variable of int instead for simplicity's sake).
I am aware that I could theoretically use a separate template parameter "cT", but that would be horribly unsafe, as the caller of this function need not pass an object of "const T" as second argument ...
I also understand that I could simply refrain from using templates at all and just specify this for every type.
I was just wondering if what I am trying to achieve below can be done with templates.
Thanks and have a nice day! :)
template<typename T>
bool ContainsElement(std::list<T>& findList, const T& elem)
{
for (auto& entry : findList)
{
if (entry == elem)
return true;
}
return false;
}
int main()
{
std::list<int*> myList;
const int testConst = 6;
auto pointerToTestConst = &testConst;
ContainsElement(myList, pointerToTestConst); // compiler screams
}
The issue is in incompatibility between pointers:
pointerToTestConst is of type const int* - non-const pointer to const integer. Therefore T=const int*
myList is of type list<int*>, deducing T=int*.
Since those types are not the same, compilation fails. Rightfully so, because elem would allow changing testConst if T=int*.
The issue manifests regardles you passing elem by (const) reference or value.
horribly unsafe, as the caller of this function need not pass an object of "const T" as second argument
So what? They get a compiler error about the comparison. It is no more unsafe than your code right now. I would argue that a generic ContainsElement should not care what you pass to is as long as it compares equal to some element in the list, it is a match.
Of course STL already offers this for std::find and std::ranges::find which also does not care and it is not called unsafe because of it.
To "normalize" the type for pointers and non-pointers, std::conditional may be used, finally your template still defines single T parameter:
#include <type_traits>
template<typename T>
bool ContainsElement(std::list<T>& findList,
const std::conditional_t<
std::is_pointer<T>::value,
std::add_pointer_t<
std::add_const_t<
std::remove_pointer_t<T>
>
>,
std::add_const_t<T>
>& elem)
{
for (auto& entry : findList)
{
if (entry == elem)
return true;
}
return false;
}
Above example uses helper types with postfix _t introduced in C++14, for C++11, use std::conditional::type.
It works for std::list<int> and std::list<int*>.
Of course in case of std::list<int*> it will check whether list contains exactly the same pointer address, not the pointed value.
http://www.cplusplus.com/reference/vector/vector/push_back/ (C++11 Version)
What is the difference and/or advantages of void push_back (const value_type& val); & void push_back (value_type&& val) and which do you suggest I use?;
I don't understand how to fill in the arguments (const value_type& val) & (value_type&& val)
I don't understand the second sentence under the parameter section. (It's a bit too wordy for me to get). I do understand what val is though
It doesn't give an example I can understand real well. Can I get other examples using vectors or some video links that explain the use of the function in practice better?
http://www.cplusplus.com/reference/vector/vector/pop_back/
It doesn't give an example I can understand real well. Can I get other examples using vectors or some video links that explain the use of the function in practice better?
If you are a beginner, just read over the additional qualifiers like const, & and &&. The methods in the STL are implemented in a way, that they behave consistent over all overloads:
I will give you a small example here:
std::vector<int> myvector;
myvector.push_back(5);
int five = 5;
myvector.push_back(five);
Now the more in depth part of the answer:
First (const value_type& val). The & character signals, that we take the argument by reference, that means we don't copy the argument, but get a fancy pointer, that will behave like the object itself.
You may not want, that your variable is changed, if you push it back to a vector. To get a promise, by the programmer of the STL, that he will not change your variable while pushing it back to the vector, he can add the const before the type.
The reason it is implemented that way, is that it may prevent an unneeded copy. (First copy the argument onto the stack to call push_back and the second time copy it at the position in the vector. The first copy is unnecessary and saved by the const reference.)
This is all nice and simple, but there are cases, where the compiler is not allowed to take a reference of a value and pass it to a function. In case of temporary values, there is no reference to take, because there is no variable in memory. Take the following line for example.
myvector.push_back(5);
Since the 5 has no address, it can't be passed as a reference. The compiler can not use the first overload of the function. But the programmer also does not want to waste the time for the copy onto the stack. That is why C++11 added new semantic. A so called rvalue for such temporary objects. If you want to write a function to take such an rvalue, you can do so by using type&& rvalue_variable. The value in this case the 5 is moved onto the stack by using the move constructor of the type. For trivial types like int, this will be the same as the copy constructor. For complex types like std::vector there are shortcuts one can take if one is allowed to rip the temporary object apart. In case of the vector, it does not need to copy all the data in the vector to a new location, but can use the pointer of the old vector in the new object.
Now we can look at the example again:
std::vector<int> myvector;
myvector.push_back(5); // push_back(const int&) can't be applied. The compiler chooses push_back(int&&) for us
int five = 5;
myvector.push_back(five); // push_back(const int&) can be applied and is used by the compiler
// The resulting vector after this has the two values [5, 5]
// and we see, that we don't need to care about it.
This should show you how you can use both of them.
push_back():
std::vector<int> vec = { 0, 1, 2 };
vec.push_back(3);
pop_back():
vec.pop_back();
vec.pop_back();
If you need more clarification:
push_back(const T& val) adds its parameter to the end of the vector, effectively increasing the size by 1 iff the vector capacity will be exceeded by its size.
pop_back() doesn't take any parameters and removes the last element of the vector, effectively reducing the size by 1.
Update:
I'm trying to tackle your questions one by one, if there is anything unclear, let me know.
What is the difference and/or advantages of void push_back (const value_type& val); & void push_back (value_type&& val) and which do you suggest I use?;
Prior to C++11, rvalue-references didn't exist. That's why push_back was implemented as vector.push_back(const value_type& val). If you have a compiler that supports C++11 or later, std::vector.push_back() will be overloaded for const lvalue references and rvalue references.
I don't understand how to fill in the arguments (const value_type& val) & (value_type&& val)
You as a programmer do NOT choose how you pass arguments to push_back(), the compiler does it for you automagically, in most cases.
I don't understand the second sentence under the parameter section. (It's a bit too wordy for me to get). I do understand what val is though
value_type is equal to the type of vector that you declared. If a vector is declared with std::string, then it can only hold std::string.
std::vector<std::string> vec;
vec.push_back("str"); // Ok. "str" is allowed.
vec.push_back(12); // Compile-time error. 12 is not allowed.
What is the difference and/or advantages of void push_back (const value_type& val); & void push_back (value_type&& val) and which do you suggest I use?
void push_back(const value_type&) takes an argument, that is then copied into the vector. This means that a new element is initialized as a copy of the passed argument, as defined by an appropriate allocator.
void push_back(value_type&&) takes an argument, that is then moved into the container (this type of expressions are called rvalue expressions).
The usage of either of two depends on the results you want to achieve.
I don't understand how to fill in the arguments (const value_type& val) & (value_type&& val)
In most cases you shouldn't think about which version to use, as compiler will take care of this for you. Second version will be called for any rvalue argument and the first one for the rest. In a rare case when you want to ensure the second overload is called you can use std::move to explicitly convert the argument expression into xvalue (which is a kind of rvalues).
I don't understand the second sentence under the parameter section. (It's a bit too wordy for me to get). I do understand what val is though
The sentence in question is:
Member type value_type is the type of the elements in the container, defined in vector as an alias of its first template parameter (T).
This means that value_type is the same type as the type of vector's elements. E.g., if you have vector<int> then value_type is the same as int and for vector<string> the value_type is string.
Because vector is not an ordinary type, but a template, you must specify a type parameters (which goes into angle brackets <> after vector) when defining a variable. Inside the vector template specification this type parameter T is then aliased with value_type:
typedef T value_type;
It doesn't give an example I can understand real well. Can I get other examples using vectors or some video links that explain the use of the function in practice better?
The main thing you need to remember is that vector behaves like a simple array, but with dynamicly changeable size and some additional information, like its length. push_back is simply a function that adds a new element at the end of this pseudo-array. There is, of course, a lot of subtle details, but they are inconsequential in most of the cases.
The basic usage is like this:
vector<int> v; // v is empty
v.push_back(1); // v now contains one element
vector<float> v2 { 1.0, 2.0 }; // v2 is now a vector with two elements
float f = v2.pop_back(); // v2 now has one element, and f is now equals 2.0
The best way to understand how it works is to try using it yourself.
I'm new here and this is my first question.
So, I have this function:
std::string join(string_initializer_list p_input) const {
std::string output;
for (auto const & s : p_input) {
output.append(s);
}
return output;
}
The main objective of that function is to join a list of strings returning a new string.
For the parameter I've used a std::initializer_list<std::string> aliased as string_initializer_list.
The parameter is passed by value because after doing a bit of research, I noticed that I was just passing pointers around and that this was the most idiomatic and correct way to do so.
My question has to do with the for loop: which is more correct in this case and why? Should I use auto const & or auto &&?
The thing is: I don't want to change any of the strings from the initializer_list, and I want to leave that clear. From that perspective const & seems more correct but I would to know your opinions about this matter.
After doing some research, testing it in C++ and reading lots of questions here, I don't yet fully understand how auto && works.
Also, in a first draft I also had the parameter being passed as && as a way to prevent it from being an lvalue.
I intend only to use this function for quick stuff like this:
join({"Hello, ", "world"});
In rare ocasions, one of those std::strings will end up being an lvalue:
join({"Hello, ", some_string});
The main concept here is to make a cheap and easy way of concatenating strings. This is another function I made, similar with the one above but for a different context.
std::string & concatenate(std::string & p_output, string_initializer_list p_input) const {
for (auto const & s : p_input) {
p_output.append(s);
}
return p_output;
}
Once more, the perfectionist in me is asking about that for loop.
The iterator type of std::initializer_list<T> is const T*. So when you dereference it, you get an lvalue of type const T. It does not matter whether you use const auto& or auto&& to iterate since either way you will get an lvalue reference to const T. I would prefer const auto& here for readability---auto&& often suggests you're working with template code in which the thing could be either an lvalue or an rvalue.
I have 2 vectors
std::vector<MyObj> v;
std::vector<MyObj2> z;
The objects in the vectors both contain an int that has an ID. I want to see if when looking through v it has a matching id in z
So I thought that I could use `std::find_if and a Lambda.
for (int i=0; i < _z.size(); i++)
{
MyObj2 _g = _z.at(i);
auto iter = std::find_if(v.begin(), v.end(), [this](MyObj o)
{
if (o.getID() == _g.getID())
{
std::cout << "we have a match" << std::endl;
}
else
{
std::cout << "we DO NOT have a match" << std::endl;
}
});
}
but I am getting an error that I dont understand.
43: Member function 'getID' not viable: 'this' argument has type 'const MyObj2', but function is not marked const
I dont understand what has to be marked const and why?
an I needing something like in my .hpp?:
MyObj2& operator= (const MyObj2&);
MyObj2& operator== (const MyObj2&);
From cppreference about find_if:
UnaryPredicate must meet the requirements of Predicate.
wich liks to the concept of Predicate:
The Predicate concept describes a function object that takes a single iterator argument that is dereferenced and used to return a value testable as a bool.
In other words, if an algorithm takes a Predicate pred and an iterator first, it should be able to test the iterator using the predicate via a construct like if (pred(*first)) {...}.
The function object pred shall not apply any non-constant function through the dereferenced iterator. This function object may be a pointer to function or an object of a type with an appropriate function call operator.
There are two requirements stated in that text:
Your predicate (i.e. the lambda) has to return something convertible to bool. Some output to cout is not sufficient.
Your predicate is not allowed to call nonconst functions on the argument (i.e. the MyObj)
However, your code shows lots of compile errors but nothing that relates to the error you stated in your question. This is because you did not provide an SSCCE:
You did not capture _g in the lambda expression
You get compile errors if the predicate does not return something convertible to bool (see requirements for the predicate above)
you mismatched z and _z
I do not get the errors you described, because in your example code you copy the values from the vectors instead of taking a const reference. Copying is fine of course, and you can apply any non-const functions to those copies. I have a compileable mini-example of your code here: http://ideone.com/o8tPED
However, this is not how it should be implemented:
You should take references instead of copies of the vector elements (I am almost sure you do that in reality)
To avoid the error you reported, you will then have to declare both getID functions const. You should do that regardless of the usage in the algorithm, because functions that don't change the object should always say so.
You need to declare MyObj2::getID() as const: The compiler says so quite clearly:
struct MyObj2 {
int getID() const { ... }
...
};
It seems, your got a member _g for which this is captured. The _g mentioned before in this example is not captured because the capture clause explicitly restricts the capture to this. If you used the _g from the scope, getID() wouldn't need to be const.
I generally prefer constness, but recently came across a conundrum with const iterators that shakes my const attitude annoys me about them:
MyList::const_iterator find( const MyList & list, int identifier )
{
// do some stuff to find identifier
return retConstItor; // has to be const_iterator because list is const
}
The idea that I'm trying to express here, of course, is that the passed in list cannot/willnot be changed, but once I make the list reference const I then have to use 'const_iterator's which then prevent me from doing anything with modifing the result (which makes sense).
Is the solution, then, to give up on making the passed in container reference const, or am I missing another possibility?
This has always been my secret reservation about const: That even if you use it correctly, it can create issues that it shouldn't where there is no good/clean solution, though I recognize that this is more specifically an issue between const and the iterator concept.
Edit: I am very aware of why you cannot and should not return a non-const iterator for a const container. My issue is that while I want a compile-time check for my container which is passed in by reference, I still want to find a way to pass back the position of something, and use it to modify the non-const version of the list. As mentioned in one of the answers it's possible to extract this concept of position via "advance", but messy/inefficient.
If I understand what you're saying correctly, you're trying to use const to indicate to the caller that your function will not modify the collection, but you want the caller (who may have a non-const reference to the collection) to be able to modify the collection using the iterator you return. If so, I don't think there's a clean solution for that, unless the container provides a mechanism for turning a const interator into a non-const one (I'm unaware of a container that does this). Your best bet is probably to have your function take a non-const reference. You may also be able to have 2 overloads of your function, one const and one non-const, so that in the case of a caller who has only a const reference, they will still be able to use your function.
It's not a trap; it's a feature. (:-)
In general, you can't return a non-const "handle" to your data from a const method. For example, the following code is illegal.
class Foo
{
public:
int& getX() const {return x;}
private:
int x;
};
If it were legal, then you could do something like this....
int main()
{
const Foo f;
f.getX() = 3; // changed value of const object
}
The designers of STL followed this convention with const-iterators.
In your case, what the const would buy you is the ability to call it on const collections. In which case, you wouldn't want the iterator returned to be modifiable. But you do want to allow it to be modifiable if the collection is non-const. So, you may want two interfaces:
MyList::const_iterator find( const MyList & list, int identifier )
{
// do some stuff to find identifier
return retConstItor; // has to be const_iterator because list is const
}
MyList::iterator find( MyList & list, int identifier )
{
// do some stuff to find identifier
return retItor;
}
Or, you can do it all with one template function
template<typename T>
T find(T start, T end, int identifier);
Then it will return a non-const iterator if the input iterators are non-const, and a const_iterator if they are const.
What I've done with wrapping standard algorithms, is have a metaobject for determining the type of container:
namespace detail
{
template <class Range>
struct Iterator
{
typedef typename Range::iterator type;
};
template <class Range>
struct Iterator<const Range>
{
typedef typename Range::const_iterator type;
};
}
This allows to provide a single implementation, e.g of find:
template <class Range, class Type>
typename detail::Iterator<Range>::type find(Range& range, const Type& value)
{
return std::find(range.begin(), range.end(), value);
}
However, this doesn't allow calling this with temporaries (I suppose I can live with it).
In any case, to return a modifiable reference to the container, apparently you can't make any guarantees what your function does or doesn't do with the container. So this noble principle indeed breaks down: don't get dogmatic about it.
I suppose const correctness is more of a service for the caller of your functions, rather that some baby-sitting measure that is supposed to make sure you get your simple find function right.
Another question is: how would you feel if I defined a following predicate and then abused the standard find_if algorithm to increment all the values up to the first value >= 3:
bool inc_if_less_than_3(int& a)
{
return a++ < 3;
}
(GCC doesn't stop me, but I couldn't tell if there's some undefined behaviour involved pedantically speaking.)
1) The container belongs to the user. Since allowing modification through the predicate in no way harms the algorithm, it should be up to the caller to decide how they use it.
2) This is hideous!!! Better implement find_if like this, to avoid this nightmare (best thing to do, since, apparently, you can't choose whether the iterator is const or not):
template <class Iter, class Pred>
Iter my_find_if(Iter first, Iter last, Pred fun)
{
while (first != last
&& !fun( const_cast<const typename std::iterator_traits<Iter>::value_type &>(*first)))
++first;
return first;
}
Although I think your design is a little confusing (as others have pointed iterators allow changes in the container, so I don't see your function really as const), there's a way to get an iterator out of a const_iterator. The efficiency depends on the kind of iterators.
#include <list>
int main()
{
typedef std::list<int> IntList;
typedef IntList::iterator Iter;
typedef IntList::const_iterator ConstIter;
IntList theList;
ConstIter cit = function_returning_const_iter(theList);
//Make non-const iter point to the same as the const iter.
Iter it(theList.begin());
std::advance(it, std::distance<ConstIter>(it, cit));
return 0;
}
Rather than trying to guarantee that the list won't be changed using the const keyword, it is better in this case to guarantee it using a postcondition. In other words, tell the user via comments that the list won't be changed.
Even better would be using a template that could be instantiated for iterators or const_iterators:
template <typename II> // II models InputIterator
II find(II first, int identifier) {
// do stuff
return iterator;
}
Of course, if you're going to go to that much trouble, you might as well expose the iterators of MyList to the user and use std::find.
If you're changing the data directed by the iterator, you're changing the list.
The idea that I'm trying to express here, of course, is that the passed in list cannot/willnot be changed, but once I make the list reference const I then have to use 'cons_iterator's which then prevent me from doing anything with the result.
What is "dong anything"? Modifying the data? That's changing the list, which is contradictory to your original intentions. If a list is const, it (and "it" includes its data) is constant.
If your function were to return a non-const iterator, it would create a way of modifying the list, hence the list wouldn't be const.
You are thinking about your design in the wrong way. Don't use const arguments to indicate what the function does - use them to describe the argument. In this case, it doesn't matter that find() doesn't change the list. What matters is that find() is intended to be used with modifiable lists.
If you want your find() function to return a non-const iterator, then it enables the caller to modify the container. It would be wrong for it to accept a const container, because that would provide the caller with a hidden way of removing the const-ness of the container.
Consider:
// Your function
MyList::iterator find(const MyList& list, int identifier);
// Caller has a const list.
const MyList list = ...
// but your function lets them modify it.
*( find(list,3) ) = 5;
So, your function should take a non-const argument:
MyList::iterator find(MyList& list, int identifier);
Now, when the caller tries to use your function to modify her const list, she'll get a compilation error. That's a much better outcome.
If you're going to return a non-const accessor to the container, make the function non-const as well. You're admitting the possibility of the container being changed by a side effect.
This is a good reason the standard algorithms take iterators rather than containers, so they can avoid this problem.