C++ replacement: Replacing every occurence of v[x] with v.at(x) - c++

In C++, for a vector v, v.at(x) behaves like v[x], except that it throws an out of bounds error if a non-existent element is accessed.
I would like to ideally always use v.at(x), however, it is not as convenient to write as v[x]. Is there a way I can make v[x] behave like v.at(x), perhaps using something like #define?
If not, is there a better solution for out-of-bounds errors to always be thrown?

You may consider overloading the method in a new inheritance, as follows
#include <iostream>
#include <vector>
template< class T, class allocator = std::allocator<T>>
struct Vector : std::vector<T, allocator>{
using std::vector<T, allocator>::vector;
const T& operator[](size_t i)const{
return this -> at(i);
}
T& operator[](size_t i){
return this -> at(i);
}
};
template< class T>
Vector(size_t, T ) -> Vector<T>;//if u want to use c++17 deduction guides
int main()
{
std::vector<int> vec1(4,1);
std::cout << vec1[4];
Vector vec2(4,1);
std::cout << vec2[4];
}

You can use a proxy object with operator [] that calls method at(). Of course, this is not exactly what you want, but the syntax is similar: instead of v[x] you have to write at(v)[x].
Proof of concept:
#include <iostream>
#include <vector>
template<class T>
class AtProxy
{
public:
AtProxy(const AtProxy<T>& proxy) : m_obj{proxy.m_obj} {}
AtProxy(T& obj) : m_obj{obj} {}
typename T::reference operator [](size_t index)
{
return m_obj.at(index);
}
private:
T& m_obj;
};
template<class T>
AtProxy<T> at(T& v)
{
return AtProxy<T>(v);
}
int main()
{
try
{
std::vector<int> vec = {1,2,3,4,5};
for(size_t i = 0; i < 5; i++)
{
std::cout << i << std::endl;
at(vec)[i] = at(vec)[i + 1] + 1;
}
}
catch(std::exception& e)
{
std::cout << "exception: " << e.what() << std::endl;
}
std::cout << "ok" << std::endl;
return 0;
}

Related

How can you iterate over elements of a std::tuple with a shared base class?

Assume you have a std::tuple with a common base class:
class MyBase { public: virtual int getVal() = 0; };
class MyFoo1: public MyBase { public: int getVal() override { return 101; } };
class MyFoo2: public MyBase { public: int getVal() override { return 202; } };
using MyTuple = std::tuple<MyFoo1, MyFoo2, MyFoo1>;
How do you iterate over the elements of the tuple at runtime? The usual answer is that you can't because they all have different types, but here I'm happy for a static type of MyBase*. I'm hoping for code like this:
MyTuple t;
for (Base* b : iterate_tuple<MyBase>(t)) {
std::cout << "Got " << b->getVal() << "\n";
}
There are a lot of helpful ideas over at How can you iterate over the elements of an std::tuple?, but they all include the code to run at each iteration in the fiddly template code, whereas I'd like all the fiddly template code bundled into the hypothetical iterate_tuple function so my code is just a normal for loop.
Here's a little wrapper function that gets the tuple value by index, specified at runtime, which does a linear search for the right index by recursively calling itself with a different template parameter. You specify its return type as a template parameter, and the value gets implicitly converted to it.
template <class BaseT, class TupleT, size_t currentIndex = 0>
BaseT* getBasePtr(TupleT& t, size_t desiredIndex) {
if constexpr (currentIndex >= std::tuple_size<TupleT>::value) {
return nullptr;
}
else {
if (desiredIndex == currentIndex) {
return &std::get<currentIndex>(t);
}
else {
return getBasePtr<BaseT, TupleT, currentIndex + 1>(t, desiredIndex);
}
}
}
You can then use it in a loop over the indices of the tuple:
for (size_t i = 0; i < std::tuple_size<MyTuple>::value; ++i) {
MyBase* b = getBasePtr<MyBase>(t, i);
std::cout << "At " << i << " got " << b->getVal() << "\n";
}
It's not quite as neat as a range-based for loop but it's still pretty straightforward to use. (You could wrap it in an iterator class that would support range-based loops but I don't really think it's worth the effort.)
As mentioned and suggested in the question linked to using std::apply is a good way to get each individual element of the tuple.
Making a small helper function to wrap the forwarding of each tuple element makes it easy to use.
It's not the specific for-loop syntax you asked for, but it's as easy to follow if you ask me.
#include <tuple>
#include <utility>
#include <iostream>
class MyBase { public: virtual int getVal() = 0; };
class MyFoo1: public MyBase { public: int getVal() override { return 101; } };
class MyFoo2: public MyBase { public: int getVal() override { return 202; } };
using MyTuple = std::tuple<MyFoo1, MyFoo2, MyFoo1>;
template <typename Tuple, typename Callable>
void iterate_tuple(Tuple&& t, Callable c) {
std::apply([&](auto&&... args){ (c(args), ...); }, t);
}
int main() {
MyTuple t;
iterate_tuple(t, [](auto& arg) {
std::cout << "Got " << arg.getVal() << "\n";
});
iterate_tuple(t, [](MyBase& arg) {
std::cout << "Got " << arg.getVal() << "\n";
});
}
We can get the exact type by using auto or use the common base type.
As Sam suggests in the comments, it's quite simple to create an array from a tuple.
template<typename Base, typename Tuple, size_t... Is>
std::array<Base *, std::tuple_size_v<Tuple>> iterate_tuple_impl(Tuple& tuple, std::index_sequence<Is...>)
{
return { std::addressof(std::get<Is>(tuple))... };
}
template<typename Base, typename Tuple>
std::array<Base *, std::tuple_size_v<Tuple>> iterate_tuple(Tuple& tuple)
{
return iterate_tuple_impl(tuple, std::make_index_sequence<std::tuple_size_v<Tuple>>{});
}
If you have inheritance, why not to do without tuple and use inheritance capabilities like this:
#include <iostream>
#include <vector>
class MyBase { public: virtual int getVal() = 0; };
class MyFoo1 : public MyBase { public: int getVal() override { return 101; } };
class MyFoo2 : public MyBase { public: int getVal() override { return 202; } };
int main() {
std::vector<std::unique_ptr<MyBase>> base;
base.emplace_back(new MyFoo1);
base.emplace_back(new MyFoo2);
for (auto && derived : base) {
std::cout << derived->getVal() << std::endl;
}
}
I would directly use std::apply, but you can create array of Base*:
template <typename Base, typename Tuple>
std::array<Base*, std::tuple_size<Tuple>> toPtrArray(Tuple& tuple)
{
return std::apply([](auto& ... args){ return std::array<Base*, std::tuple_size<Tuple>>{{&args}}; }, tuple);
}
And then
MyTuple t;
for (Base* b : toPtrArray<MyBase>(t)) {
std::cout << "Got " << b->getVal() << "\n";
}

How to pass index information to element constructor when using std::vector?

Is there any way I can pass vector's index to an constructor of it's element?
for example:
#include <iostream>
#include <vector>
class Foo {
public:
Foo(unsigned long index) {
std::cout << index << std::endl;
}
};
int main() {
std::vector<Foo> foo;
foo.resize(2); // any way to make this work?
}
this code does of cause not work because the compiler don't know how to construct a Foo(unsigned long index), but any way I can do some tricks(for example to custom an allocator?) to make this code actually work?
You can add elements in a for loop and pass the index as an argument to their ctors like this:
// Init your vector + optionally reserve space
std::vector<Foo> foo;
const unsigned elements_to_add = 5; // or whatever number
foo.reserve(foo.size() + elements_to_add);
// foo.size() will be passed as parameter to the ctor you defined
for (std::size_t i = 0; i < elements_to_add; i++) {
foo.emplace_back(foo.size());
}
No, you will want to use std::generate() , or std::generate_n() in combination with std::back_inserter().
You can write a custom statefull allocator that will pass an index when an object is constructed.
Minimal example:
template<class T>
class Allocator {
public:
using value_type = T;
T* allocate(std::size_t n) {
return static_cast<T*>(::operator new(n * sizeof(T)));
}
void deallocate(T* p, std::size_t) noexcept {
::operator delete(p);
}
template<class... Args>
void construct(T* p, Args&&... args) {
::new(static_cast<void*>(p)) T(counter_++, std::forward<Args>(args)...);
}
void destroy(T* p) noexcept {
p->~U();
--counter_;
}
private:
std::size_t counter_ = 0;
};
Usage example:
struct Foo {
Foo(std::size_t index) {
std::cout << index << ' ';
}
Foo(std::size_t index, const Foo& other) : Foo(other) {
std::cout << index << ' ';
}
};
std::vector<Foo, Allocator<Foo>> foos1;
foos1.resize(3);
std::cout << std::endl;
std::vector<Foo, Allocator<Foo>> foos2;
foos2.resize(4);
// Output:
// 0 1 2
// 0 1 2 3
I guess there are many ways to get more or less what you want. But sooner or later, you'll probably find out that you won't need this.
Here is a possible solution:
#include <iostream>
#include <vector>
class Foo
{
inline static unsigned long _static_index = 0;
unsigned long _index;
public:
Foo() : _index(_static_index) { ++_static_index; }
auto index() const { return _index; }
static void resetIndex() { _static_index = 0; }
};
int main()
{
std::vector<Foo> foos;
Foo::resetIndex();
foos.resize(2);
for (const auto& f : foos)
std::cout << f.index() << std::endl;
return 0;
}
So, you just increment a static counter and assign it to the private member _index. This obviously has its limitations. For instance, say you create 3 instances of Foo before filling your vector of Foos, then foos[0].index() would return 3 instead of 0. So, before filling foos, you would need to reset the _static_index.

C++ - How to determine the type of the return value of a function?

I'm trying to build a vector of objects that have two properties, the key is always a String, and the value is always of type T
When I iterate through the vector, I need to be able to determine the type of the value property so that I can switch in a case statement to process it.
How do I determine the type of the return value of value get function of the vector object?
My class is here:
template <class T>
class IEFIAttribute
{
String key;
T value;
public:
IEFIAttribute(String key, T value)
{
this->key = key;
this->value = value;
}
String getKey();
T getValue();
};
template <class T>
String IEFIAttribute<T>::getKey()
{
return this->key;
}
template <class T>
T IEFIAttribute<T>::getValue()
{
return this->value;
}
And in my main.cpp, the following works:
...
IEFIAttribute <String> att("testkey","testvalue");
Serial.println("XXX Key: "+att.getKey());
Serial.println("XXX Value: "+att.getValue());
...
The result of running that is:
XXX Key: testkey
XXX Value: testvalue
What I want to be able to do is switch on the type of att.getValue() so that if it is a String, I do one thing, if it is xyz object, I process it according to my rules for xyz objects.
Any help will be very appreciated!
Kind regards!
#include <iostream>
#include <string>
#include <type_traits>
#include <vector>
using String = std::string;
template<class T>
class IEFIAttribute {
public:
using value_type = T; // add this to be able to query it later
IEFIAttribute(const String& Key, const T& Value) :
key(Key), // prefer using the member initializer list
value(Value)
{}
// instead of copies, return const references
String const& getKey() const {
return key;
};
T const& getValue() const {
return value;
}
private:
String key;
T value;
};
You have many possibilities to do special handling for certain types.
A template using constexpr if:
template<typename T>
T special_1(const std::vector<IEFIAttribute<T>>& v, size_t idx) {
if constexpr(std::is_same_v<T, String>) {
std::cout << "special_1() String handler\n";
} else if constexpr(std::is_same_v<T, int>) {
std::cout << "special_1() int handler\n";
} else {
std::cout << "special_1() generic handler\n";
}
return v[idx].getValue();
}
A template with specializations:
template<typename T>
T special_2(const std::vector<IEFIAttribute<T>>& v, size_t idx) {
std::cout << "special_2() generic handler\n";
return v[idx].getValue();
}
template<>
String special_2(const std::vector<IEFIAttribute<String>>& v, size_t idx) {
std::cout << "special_2() String handler\n";
return v[idx].getValue();
}
template<>
int special_2(const std::vector<IEFIAttribute<int>>& v, size_t idx) {
std::cout << "special_2() int handler\n";
return v[idx].getValue();
}
Or using the added value_type to do queries:
int main() {
std::vector<IEFIAttribute<String>> v1{{"testkey", "testvalue"}};
std::vector<IEFIAttribute<int>> v2{{"testkey", 10}};
// decltype(v1)::value_type is the vectors value_type
// and the second value_type is the one added to your class
if(std::is_same_v<decltype(v1)::value_type::value_type, String>) {
std::cout << "is String\n";
} else {
std::cout << "is not String\n";
}
if(std::is_same_v<decltype(v2)::value_type::value_type, int>) {
std::cout << "is int\n";
} else {
std::cout << "is not int\n";
}
std::cout << special_1(v1, 0) << "\n";
std::cout << special_1(v2, 0) << "\n";
std::cout << special_2(v1, 0) << "\n";
std::cout << special_2(v2, 0) << "\n";
}
One way to accomplish what you need is to use a typedef inside your class, and then functions of <type_traits> for you conditional statements.
For example:
template <class T>
class IEFIAttribute
{
public:
typedef T value_type;
// everything as before...
};
then
if (std::is_same<att::value_type, String>)
// .. do something

Is there any way to implement Initializer lists (kind of) in older version of c++ (Before c++11)?

i have tried to implement (kind of :) Initializer lists in older version of c++. like below..
#include <vector>
#include <cstdarg>
#include <iostream>
using namespace std;
template <class T>
vector <T> VEC_VA(size_t argCount,T arg1, ... )
{
va_list arguments;
vector <T> sList;
va_start ( arguments, argCount);
for ( int x = 0; x < (int)argCount; x++ )
sList.push_back(va_arg ( arguments, T));
va_end ( arguments );
return sList;
}
struct Test
{
Test(int _x,std::string _s):x(_x),s(_s){}
int x;
std::string s;
};
void methodWithArgs(vector<Test> testObjs)
{
cout<<"Size:"<<testObjs.size()<<endl;
for (std::vector<Test>::const_iterator it = testObjs.begin();it != testObjs.end();++it)
std::cout << it->x <<":"<< it->s.c_str()<< std::endl;
}
int main()
{
methodWithArgs(VEC_VA(2,Test(1,"one"),Test(2,"two")));
return 0;
}
But this kind of implementation works in Visual studio 2012 (v11.0). But not in Linux g++ compiler. And ended with an Error: "cannot pass objects of non-trivially-copyable type ‘struct Test’ through ‘...’"
So is there any better idea?
If you are willing to accept a slightly different syntax then all you need is a version of vector::push_back() that returns a reference to the vector. Something like this:
#include <vector>
#include <iostream>
template<typename T>
class VEC_VA_HELP {
std::vector<T> vector;
public:
VEC_VA_HELP(T arg1) : vector() { vector.push_back(arg1); }
VEC_VA_HELP &operator()(T arg) { vector.push_back(arg); return *this; }
operator std::vector<T> &() { return vector; }
};
template<typename T>
VEC_VA_HELP<T> VEC_VA(T arg1) { return VEC_VA_HELP<T>(arg1); }
struct Test {
Test(int _x) : x(_x) {}
int x;
};
void methodWithArgs(std::vector<Test> const &testObjs) {
std::cout << testObjs.size() << std::endl;
for (std::vector<Test>::const_iterator it = testObjs.begin();
it != testObjs.end();
++it)
std::cout << it->x << std::endl;
}
int
main(void)
{
methodWithArgs(VEC_VA(Test(1))(Test(2))(Test(3)));
return 0;
}
Also recursive templates come to mind but I am not sure how clean the syntax would be with them. See also this question about overloading the comma operator.
Same as like this above answer by daniel But some improvements
template <class T>
class VECS
{
vector <T> vec;
public:
VECS(){}
VECS(T t){vec.push_back(t);}
VECS& operator()(const T& t){vec.push_back(t);return *this;}
typedef VECS<T> myVECS;
myVECS& operator<< (const T& t){vec.push_back(t);return *this;}
operator vector<T>() const {return vec;}
};
Usage
methodWithArgs(VECS<Test>(Test(1,"one"))(Test(2,"two")));
methodWithArgs(VECS<Test>()<<Test(1,"one")<<Test(2,"two"));
methodWithArgs(VECS<Test>(Test(0,"zero")) <<Test(1,"one")<<Test(2,"two"));
std::vector<int> v1 = VECS<int>() << 1 << 2 << 3;
std::vector<int> v2 = VECS<int>(1)(2)(3);

range based for loop with const shared_ptr<>

I have a container with shared_ptr<>, e.g. a vector<shared_ptr<string>> v and I'd like to iterate over v indicating const-ness.
This code:
vector<shared_ptr<string>> v;
v.push_back(make_shared<std::string>("hallo"));
...
for (const auto &s : v) {
*s += "."; // <<== should be invalid
}
looks like what I want to do (indicating that s is const) but of course it does not make the string const.
Is there an elegant way to iterate over a container of shared_ptr which makes clear that the content won't be modified?
Something like
for (shared_ptr<const string> s : v) {
*s += "."; // <<== will not compile
}
(but this code would not compile for other reasons :))
Edit:
I made a mistake. Originally I was declaring a reference, which results in a compiler error
for (shared_ptr<const string> &s : v) { // <<== does not compile
...
}
If you declare a shared_ptr<const string> the example works. In my eyes this is a good trade-off but this way the pointer gets copied which can be time consuming in loops with little code and big containers..
This is a well-known limitation of C++ that some don't consider to be a limitation.
You want to iterate constly, but an immutable pointer doesn't imply an immutable pointee.
The type shared_ptr<string> and the type shared_ptr<const string> are effectively unrelated.
Option 1
for (const auto& ptr : v) {
const auto& s = *ptr;
s += "."; // <<== is invalid
}
Option 2
Just don't modify it.
Here is the answer.
But first, the sermon:
A pointer and the thing it points to are two separate objects. Either, none or both may be const and a const pointer simply means that it will not point to a different thing. If the pointee is const, the object may not be changed through the (possibly non-const) pointer.
Having said that, we (I) often write value-semantic wrapper objects that use unique_ptr or shared_ptr as the pimpl. Often we wish to propogate the constness of the wrapper to impl.
I believe c++17 will solve this with it's propagate_const pointer wrapper.
In the meantime it's straightforward to build your own:
#include <iostream>
#include <type_traits>
#include <memory>
#include <string>
#include <vector>
namespace traits
{
template<class T> struct pointee;
template<class T, class D>
struct pointee<std::unique_ptr<T, D>> {
using type = T;
};
template<class T>
struct pointee<std::shared_ptr<T>> {
using type = T;
};
template<class T> using pointee_t = typename pointee<T>::type;
}
template<class PointerType>
struct propagate_const
{
using pointer_type = PointerType;
using element_type = traits::pointee_t<pointer_type>;
using value_type = std::decay_t<element_type>;
using reference = value_type&;
using const_reference = const value_type&;
propagate_const(pointer_type p) : _ptr(std::move(p)) {}
const_reference operator*() const {
return *_ptr;
}
auto operator*()
-> std::enable_if_t<not std::is_const<element_type>::value, reference>
{
return *_ptr;
}
private:
pointer_type _ptr;
};
template<class PointerType>
auto make_propagating_pointer(PointerType&& p)
{
return propagate_const<PointerType>(std::forward<PointerType>(p));
}
int main()
{
using namespace std;
vector<propagate_const<shared_ptr<string>>> v;
v.emplace_back(make_shared<string>("hello"));
for (const auto& p : v)
{
// *p += " there"; // compile error
cout << *p;
cout << endl;
}
for (auto& p : v)
{
*p += " there";
cout << *p;
cout << endl;
}
return 0;
}
expected output:
hello
hello there
This one is very simple, supporting only operator* but it's trivial to add a complete set of operators. Note that I disable mutable access when the pointee is const.
reference: http://en.cppreference.com/w/cpp/experimental/propagate_const
And just for fun, here's a complete example of a shared_string class that uses shared_ptr internally and propagates constness correctly.
#include <iostream>
#include <type_traits>
#include <memory>
#include <string>
#include <vector>
template<class PointerType>
struct propagate_const
{
using pointer_type = PointerType;
using element_type = std::remove_reference_t<decltype(*std::declval<PointerType&>())>;
using reference = element_type&;
using const_reference = const element_type&;
propagate_const(pointer_type p) : _ptr(std::move(p)) {}
const_reference operator*() const {
return *_ptr;
}
auto operator*()
-> std::enable_if_t<not std::is_const<element_type>::value, reference>
{
return *_ptr;
}
private:
pointer_type _ptr;
};
template<class PointerType>
auto make_propagating_pointer(PointerType&& p)
{
return propagate_const<PointerType>(std::forward<PointerType>(p));
}
struct shared_string
{
shared_string(std::string s) : _impl(std::make_shared<std::string>(std::move(s))) {};
shared_string(std::shared_ptr<std::string> sp) : _impl(sp) {};
shared_string(propagate_const<std::shared_ptr<std::string>> sp) : _impl(sp) {};
auto& operator += (const std::string& s) {
*_impl += s;
return *this;
}
friend std::ostream& operator<<(std::ostream& os, const shared_string& ss) {
return os << *(ss._impl);
}
private:
propagate_const<std::shared_ptr<std::string>> _impl;
};
template<class T, std::enable_if_t<std::is_const<T>::value>* = nullptr >
std::string check_const(T&)
{
return std::string("const");
}
template<class T, std::enable_if_t<not std::is_const<T>::value>* = nullptr >
std::string check_const(T&)
{
return std::string("not const");
}
int main()
{
using namespace std;
// a vector of mutable shared_strings
vector<shared_string> v;
// a vector of immutable shared_strings
vector<const shared_string> cv;
// make a shared_string
v.emplace_back(make_shared<string>("hello"));
// refer to the *same one* in cv
cv.emplace_back(v[0]);
for (const auto& p : v)
{
// *p += " there"; // immutable reference to mutable shared string - not allowed
cout << check_const(p) << " " << p;
cout << endl;
}
for (auto& p : v)
{
cout << check_const(p) << " " << p;
p += " there"; // mutable reference to mutable shared string - allowed
cout << " becomes " << p;
cout << endl;
}
for (auto&p : cv)
{
cout << check_const(p) << " " << p;
// p += " world"; // p is actually immutable because cv contains immutable objects
cout << endl;
}
return 0;
}
expected output:
const hello
not const hello becomes hello there
const hello there
I would go with template approarch
template <class T,class F>
void forEach(const std::vector<std::shared_ptr<T>>& vec, F&& f){
for (const auto& ptr : vec){
if (ptr){
f(std::cref(*ptr));
}
}
}
I you put a lambda function there, the compiler will probably inline it anyway, so no performance damage here.