boost::shared_ptr<std::vector<something>> usage of operator[] - c++11

I have a struct that looks like this.
typedef struct superCellBoxStruct {
float_tt cmx,cmy,cmz; /* fractional center of mass coordinates */
float_tt ax,by,cz;
boost::shared_ptr<std::vector<atom>> atoms; /* contains all the atoms within the super cell */
} superCellBox;
now when I want to access atoms[i] I get
error: invalid use of ‘boost::detail::sp_array_access >::type {aka void}’
What is the proper way of passing around a shared vector in my application, or what is the correct way to access its operator[]?

Pick one:
(*atoms)[i]
atoms->operator[](i);
I usually go with the first, but they are all equivalent.
As a side note, in my experience a shared_ptr<vector> like that is usually a symptom of a bad design, maybe you want to put the entire superCellBox in a shared_ptr?
Also, this is not C, use struct name {}; instead typedef struct tagName {} name;

Prefer unique_ptr<T[]> if you can, because you get operator[] for free (§ 20.7.1.3.3):
Quick demo:
Live On Coliru
#include <memory>
#include <iostream>
int main() {
std::unique_ptr<int[]> p(new int[3] { 1,2,3 });
std::cout << "Before: " << p[0] << ", " << p[1] << ", " << p[2] << ";\n";
p[1] = 42;
std::cout << "After: " << p[0] << ", " << p[1] << ", " << p[2] << ";\n";
}
Prints:
Before: 1, 2, 3;
After: 1, 42, 3;
UPDATE
In response to the comment, just make a small wrapper:
Live On Coliru
#include <memory>
template <typename RAContainer> struct shared_randomaccess_container
{
template <typename... A> shared_randomaccess_container(A&&... args)
: _ptr(new RAContainer{ std::forward<A>(args)... })
{ }
template <typename T> shared_randomaccess_container(std::initializer_list<T> init)
: _ptr(std::make_shared<RAContainer>(init))
{ }
auto begin() const -> typename RAContainer::const_iterator { return _ptr->begin(); }
auto end () const -> typename RAContainer::const_iterator { return _ptr->end (); }
auto begin() -> typename RAContainer::iterator { return _ptr->begin(); }
auto end () -> typename RAContainer::iterator { return _ptr->end (); }
template <typename Idx>
typename RAContainer::value_type const& operator[](Idx i) const { return (*_ptr)[i]; }
template <typename Idx>
typename RAContainer::value_type& operator[](Idx i) { return (*_ptr)[i]; }
template <typename Idx>
typename RAContainer::value_type const& at(Idx i) const { return _ptr->at(i); }
template <typename Idx>
typename RAContainer::value_type& at(Idx i) { return _ptr->at(i); }
protected:
using Ptr = std::shared_ptr<RAContainer>;
Ptr _ptr;
};
////////////////////////////////////////////////////
// demo intances
#include <vector>
template <typename... Ts> using shared_vector = shared_randomaccess_container<std::vector<Ts...> >;
You can use it like:
shared_vector<int> sv {1,2,3};
std::cout << "Before: ";
for (auto i : sv) std::cout << i << " ";
sv[1] = 42;
std::cout << "\nAfter: ";
for (auto i : sv) std::cout << i << " ";
Prints:
Before: 1 2 3
After: 1 42 3
Bonus
Let's also support aggregate initializing containers with the same technique
Live On Coliru
Output:
void test() [with With = std::vector<int>]
Before: 1 2 3
After: 1 42 3
void test() [with With = std::array<int, 3ul>]
Before: 1 2 3
After: 1 42 3
void test() [with With = shared_randomaccess_container<std::vector<int>, false>]
Before: 1 2 3
After: 1 42 3
void test() [with With = shared_randomaccess_container<std::array<int, 3ul>, true>]
Before: 1 2 3
After: 1 42 3

Related

Befriending a function template defined in another file in C++11?

I have written a custom vector class template and print_vector function template that is supposed to print the content of my custom vector class. The print_vector function uses v.sz and v.elem which are declared private inside the vector class. However I am unable to declare print_vector as a friend inside my vector class. I want to keep the print_vector separately defined in t_vector.cpp.
A problem is that print_vector takes a parameter of the same type as the class it is declared friend in (becomes a circular dependency?). I also get an error saying that print_vector is not declared in scope.
I have marked the problematic places with // <--
// t_vector.h
#ifndef T_VECTOR_H
#define T_VECTOR_H
#include <string>
template <typename T>
void print_vector(Vector<T>& v);
template <typename T>
struct Vector {
private:
int sz;
T* elem;
public:
Vector() = delete;
explicit Vector(int s);
Vector(const Vector<T>& v);
~Vector();
Vector<T>& operator=(const Vector<T>& v);
T& operator[](int e) const;
template<typename U>
friend void print_vector(Vector<U>& v); // <-- TRYING TO FRIEND print_vector
};
#endif
// t_vector.cpp
#include "t_vector.h"
#include <stdexcept>
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::string;
template <typename T>
Vector<T>::Vector(int s) {
if (s < 0) throw std::invalid_argument("Negative size");
cout << this << " called Vector(int s) constructor" << endl;
sz = s;
elem = new T[sz];
}
template <typename T>
Vector<T>::Vector(const Vector<T>& v) : sz{v.sz}, elem{new T[v.sz]} {
cout << this << " called Copy constructor on " << &v << endl;
for (int i = 0; i<sz; ++i) {
elem[i] = v[i];
}
}
template <typename T>
Vector<T>::~Vector() {
cout << "~" << this << " delete elem " << &elem << endl;
delete[] elem;
}
template <typename T>
Vector<T>& Vector<T>::operator=(const Vector<T>& v) {
cout << this << " called Copy assignment operator to copy " << &v << endl;
if (this != &v) {
T *tmp = new T[v.sz];
for (int i=0; i<v.sz; ++i ) {
tmp[i] = v.elem[i];
}
sz = v.sz;
delete[] elem;
elem = tmp;
}
return *this;
}
template <typename T>
T& Vector<T>::operator[](int e) const {
if (e < 0 || e >= sz) throw std::out_of_range("Vector::operator[]");
return elem[e];
}
template <typename T>
void print_vector(Vector<T>& v) { // <--- THIS FUNCTION WANTS TO READ v.sz WHICH IS PRIVATE
for (int i = 0; i < v.sz-1; ++i) {
cout << '[' << v.elem[i] << ']';
}
cout << '[' << v[v.sz-1] << ']' << endl;
}
// test_t_vector.cpp
#include "t_vector.h"
#include "t_vector.cpp"
#include <iostream>
using std::cout;
using std::endl;
int main() {
cout << "---------- Starting: test_vector ----------" << endl;
Vector<int> vec(3);
vec[2] = 5;
print_vector(vec);
cout << "---------- Exiting: test_vector ----------" << endl;
return 0;
}
Error output:
g++ -O0 -Wall -Wextra -pedantic-errors -Wold-style-cast -fno-elide-constructors -std=c++14 -g -ggdb3 -MT t_vector.o -MMD -MP -MF t_vector.d -std=c++14 -I. -c -o t_vector.o t_vector.cpp
In file included from t_vector.cpp:1:
t_vector.h:7:6: error: variable or field ‘print_vector’ declared void
7 | void print_vector(Vector<T>& v);
| ^~~~~~~~~~~~
t_vector.h:7:19: error: ‘Vector’ was not declared in this scope
7 | void print_vector(Vector<T>& v);
| ^~~~~~
t_vector.h:7:27: error: expected primary-expression before ‘>’ token
7 | void print_vector(Vector<T>& v);
| ^
t_vector.h:7:30: error: ‘v’ was not declared in this scope
7 | void print_vector(Vector<T>& v);
| ^
make: *** [<builtin>: t_vector.o] Error 1
As Ted Lyngmo and Retired Ninja mentioned the problem is that the implementation should have been visible in the header file. One of the methods to achieve this is to include a .tpp file with all the template implementations in the header file and include this file in the end of the header file. Unfortunately my class template seemed to work despite separating the class template declaration in the header file and the implementation details in a cpp file. This can occur by luck but the general rule is to show implementation details in header one way or another.

c++11 how to check template parameter pack has N args before calling function with N args

Following on from this extracting a template parameter pack with different types into a vector of doubles produces warnings and cigien's answer.
I have the following code:
enum class p_type {p1, p2, p3};
class testerx
{
public:
void process1(double a)
{
std::cout << "1" << a << std::endl;
};
void process2(double a, double b)
{
std::cout << "2" << a << " " << b << std::endl;
};
void process3(double a, double b, double c)
{
std::cout << "3" << a << " " << b << " " << c << std::endl;
};
};
// The template type
template<typename TESTER, typename... ARGS>
class tester_templatex
{
public:
explicit tester_templatex(p_type type) : m_type(type) {};
void process(ARGS... args)
{
// Create a vector to put the args into. use double since that can hold all of the types
// that I am using
size_t param_count = sizeof...(args);
std::cout << "PARAM COUNT X " << param_count << std::endl;
std::vector<double> args_vect = {static_cast<double>(args)...};
for (auto arg : args_vect)
{
std::cout << "arg: " << arg << std::endl;
}
// Now call the tester
std::cout << "running tester: ";
switch (m_type)
{
case p_type::p1:
if constexpr (sizeof...(args) == 1)
m_tester.process1(args...);
break;
case p_type::p2:
if constexpr (sizeof...(args) == 2)
m_tester.process2(args...);
break;
case p_type::p3:
if constexpr (sizeof...(args) == 3)
m_tester.process3(args...);
break;
}
std::cout << std::endl;
};
p_type m_type;
TESTER m_tester;
};
main:
int main() {
tester_templatex<testerx, int> templatex1(p_type::p1);
tester_templatex<testerx, int, double> templatex2(p_type::p2);
tester_templatex<testerx, int, double, int> templatex3(p_type::p3);
templatex1.process(4);
templatex2.process(4, 5.123);
templatex3.process(4, 5.123, 6);
return 0;
}
Here I have test class with 3 different functions. I have a template class which picks the function to call based on the p_type (bad name - dont ask!).
This works for c++17 compiled code. But I only have c++11 where I need to run this code. c++11 does not support if constexpr:
case p_type::p3:
if constexpr (sizeof...(args) == 3)
m_tester.process3(args...);
break;
Without the if constexpr I get errors that the m_tester.process1/2/3 functions that don't match the parameter pack because they don't have the right number of parameters.
How can I fix this for c++11? - is it possible with a similar method?
Is there another way to extract N arguments from a parameter pack in c++11? - or some sort of type traits check?
For each of your functions have an overload that does nothing:
template<typename... ARGS>
void process3(ARGS&...) { }
and then just call the function without testing for the size of the pack:
case p_type::p3:
m_tester.process3(args...);
break;
This should pick the non-templated function when there are suitably many arguments, and the function template in other cases.

How to use spirit X3 parse into a class with constructor containing parameters?

I am a new man on using spirit x3, I read some document from official site or from other github repositories. But, I can not find how to parse into a class with parameters. I referred to the former question: Boost-Spirit (X3) parsing without default constructors
I wrote a sample to test it, I will present my codes in the following area. My pain is how to use x3::_attr, and how to pass parsed parameters to the class constructor?
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <vector>
struct MyPair {
MyPair(int x, int y) : mx(x), my(y) {};
int mx;
int my;
};
class MyDu {
public:
MyDu() {};
MyDu(int x, int y) : mx(x), my(y) {};
int mx;
int my;
};
int main()
{
namespace x3 = boost::spirit::x3;
using x3::int_;
std::vector<MyPair> pairs;
MyDu myDu;
char const *first = "11:22", *last = first + std::strlen(first);
//auto pair = x3::rule<struct pair_, std::vector<MyPair> >{}
// = (int_ >> ':' >> int_)
// [([&](auto& ctx) {
// auto& attr = x3::_attr(ctx);
// using boost::fusion::at_c;
// return x3::_val(ctx).emplace_back(at_c<0>(attr), at_c<1>(attr));
// })]
//;
auto pair = x3::rule<class MyDu_, MyDu >{}
= (int_ >> ':' >> int_)
[([&](auto& ctx) {
auto& attr = x3::_attr(ctx);
using boost::fusion::at_c;
//return x3::_val(ctx)(at_c<0>(attr), at_c<1>(attr));
ctx = MyDu(at_c<0>(attr), at_c<1>(attr));
return x3::_val(ctx);
})]
;
//bool parsed_some = parse(first, last, pair % ',', pairs);
bool parsed_some = parse(first, last, pair, myDu);
if (parsed_some) {
std::cout << "Parsed the following pairs" << std::endl;
//for (auto& p : pairs) {
// std::cout << p.mx << ":" << p.my << std::endl;
//}
std::cout<<myDu.mx<<","<<myDu.my<<std::endl;
}
system("pause");
}
Any one who can fix my error, and parse into a class in my code ? Thanks!
Perhaps you were missing the way to assign to the rule's value using _val:
Live On Coliru
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <vector>
struct MyDu {
MyDu(int x, int y) : mx(x), my(y){};
int mx;
int my;
};
int main() {
namespace x3 = boost::spirit::x3;
using x3::int_;
MyDu myDu{1,2};
std::string const s = "11:22";
auto assign = [](auto& ctx) {
using boost::fusion::at_c;
auto& attr = x3::_attr(ctx);
x3::_val(ctx) = MyDu(at_c<0>(attr), at_c<1>(attr));
};
auto pair = x3::rule<class MyDu_, MyDu>{} = (int_ >> ':' >> int_)[assign];
if (parse(begin(s), end(s), pair, myDu)) {
std::cout << "Parsed: " << myDu.mx << ", " << myDu.my << "\n";
}
}
Prints
Parsed: 11, 22
Oh, fantastic! Many thanks, sehe, you help me solve the problem bothering me for some while.
In fact I can not find document on spirit how to use attr, i only find a doc from "Ruben-Van-Boxem-Parsing-CSS-in-C-with-Boost-Spirit-X3",
_val :A reference to the attribute of the innermost rule invoking _where :the parser Iterator range to the input stream
_attr : A reference to the a˛ribute of the parser
_pass: A reference to a bool flag that can be used to force the parser to fail
could you share some info on these parameters. Many thanks again!

Creating a C++ template function that allows multiple types of array containers

In modern C++ you can create arrays by three primary methods shown below.
// Traditional method
int array_one[] = {1, 2, 3, 4}
// Vector container
std::vector<int> array_two = {1, 2, 3, 4}
// array container
std::array<int, 4> array_three = {1, 2, 3, 4}
While each array method contains the same data, they are inherently different containers. I am writing a very simple Unit Test class with template functions to make it easier to pass multiple data types. I have an example shown below for the .hpp and .cpp calling file. The one method shown in the file takes a std::vector and compares it to another std::vector indice by indice to ensure that each value is within a certain tolerance of the other.
// main.cpp
#include <iostream>
#include <string>
#include <vector>
#include <array>
#include "unit_test.hpp"
int main(int argc, const char * argv[]) {
int array_one[] = {1, 2, 3, 4};
std::vector<int> array_two = {1, 2, 3, 4};
std::vector<float> array_four = {0.99, 1.99, 2.99, 3.99};
std::array<int, 4> array_three {1, 2, 3, 4};
std::string c ("Vector Test");
UnitTest q;
double unc = 0.1;
q.vectors_are_close(array_two, array_four, unc, c);
return 0;
}
and
#ifndef unit_test_hpp
#define unit_test_hpp
#endif /* unit_test_hpp */
#include <string>
#include <typeinfo>
#include <iostream>
#include <cmath>
class UnitTest
{
public:
template <class type1, class type2>
void vectors_are_close(const std::vector<type1> &i, const std::vector<type2> &j,
double k, std::string str);
private:
template <class type1, class type2>
void is_close(type1 &i, type2 &j, double k);
};
template <class type1, class type2>
void UnitTest::vectors_are_close(const std::vector<type1> &i, const std::vector<type2> &j,
double k, std::string str)
{
unsigned long remain;
remain = 50 - str.length();
if (i.size() != j.size()) {
std::cout << str + std::string(remain, '.') +
std::string("FAILED") << std::endl;
}
else {
try {
for (int a = 0; a < i.size(); a++){
is_close(i[a], j[a], k);
}
std::cout << str + std::string(remain, '.') +
std::string("PASSED") << std::endl;
} catch (const char* msg) {
std::cout << str + std::string(remain, '.') +
std::string("FAILED") << std::endl;
}
}
}
template <class type1, class type2>
void UnitTest::is_close(type1 &i, type2 &j, double k)
{
double percent_diff = abs((j - i) / ((i + j) / 2.0));
if (percent_diff > k) {
throw "Number not in Tolerance";
}
}
In this example the code compares two vectors; however, if I want to compare std::array containers I will have to crate a whole new function to do that, and if I want to compare two generic arrays, I will have to yet again create another function to do that. In addition, if I want to compare data in a std::array container to a std::vector container, again, I will have to create another function. I would like to create a single templated member function that I can pass any type of container to the function and have it compare it against any other type of container. In other words instead of;
void UnitTest::vectors_are_close(const std::vector<type1> &i, const std::vector<type2> & j);
I would like a simpler function such as;
void UnitTest::arrays_are_close(const type1, const type2);
where type1 and type2 do not just refer to the data in the container, but also the type of container as well. In this way I could pass a std::vector to type1 and std::array to type, or other combinations of the traditional way of creating arrays, array containers and vector containers. Is there any way to facilitate this behavior?
With a few changes to your implementation it is possible to do that:
template <class container1, class container2>
void UnitTest::vectors_are_close(const container1 &i, const container2 &j,
double k, std::string str)
{
unsigned long remain;
remain = 50 - str.length();
if (std::size(i) != std::size(j)) {
std::cout << str + std::string(remain, '.') +
std::string("FAILED") << std::endl;
}
else {
try {
for (int a = 0; a < std::size(i); a++){
is_close(i[a], j[a], k);
}
std::cout << str + std::string(remain, '.') +
std::string("PASSED") << std::endl;
} catch (const char* msg) {
std::cout << str + std::string(remain, '.') +
std::string("FAILED") << std::endl;
}
}
}
This function should work for std::vector, std::array and C-style arrays.

How to connect a boost signal for only once?

How do I achieve the Qt::UniqueConnection mechanism in Boost?
Basically, I only want to connect the signal for only once.
As far as I know, there's no such thing, but you can easily mimic it using a custom combiner.
1. Using the custom Combiner
You can just ignore any excess slots. This combiner, for example, just ignores anything beyond the first slot (that is, the first added with at_front and no group, or the first in the group with the highest priority, see Ordering Slot Call Groups):
template<typename Result>
struct call_first {
typedef boost::optional<Result> result_type;
template<typename It>
result_type operator()(It first, It last) const {
if (first != last)
return *first;
return boost::none;
}
};
Now here's a test case: Live On Coliru
#include <iostream>
#include <boost/optional/optional_io.hpp>
int foo(int i) { std::cout << "(foo)"; return i*2; }
int bar(int i) { std::cout << "(bar)"; return i+2; }
int main()
{
using namespace boost::signals2;
signal<int(int), call_first<int> > sig;
std::cout << sig(42) << "\n"; // should be none ("--")
sig.connect(foo);
std::cout << sig(42) << "\n"; // should return 42*2
sig.connect(bar);
std::cout << sig(42) << "\n"; // should still return 42*2
}
Printing
--
(foo) 84
(foo) 84
2. Fix your connection management
You can make it easy to avoid double-connecting a signal, by using pretty simple helpers (assuming c++11 for this sample):
template <typename Sig, typename F> void try_connect(Sig& sig, F&& f) {
if (!sig.num_slots()) sig.connect(std::forward<F>(f));
}
template <typename Sig, typename F> void re_connect(Sig& sig, F&& f) {
sig.disconnect_all_slots();
sig.connect(std::forward<F>(f));
}
The corresponding test case Live On Coliru:
int main()
{
using namespace boost::signals2;
signal<int(int)> sig;
std::cout << sig(42) << "\n"; // should be none ("--")
try_connect(sig, foo);
std::cout << sig(42) << "\n"; // should return 42*2
try_connect(sig, bar);
std::cout << sig(42) << "\n"; // should still return 42*2
re_connect(sig, bar);
std::cout << sig(42) << "\n"; // should return 42+2
}
Output:
--
(foo) 84
(foo) 84
(bar) 44

Resources