I've created a type
using Parameter = std::tuple<unsigned int, std::string>;
and in my class, I have a property like this (note: vector, unique_ptr and string are all included - there is no problem)
class MyClass
{
public:
std::vector<std::unique_ptr<Parameter>> parameters;
public:
explicit MyClass(const std::vector<std::string> &data);
};
with definition
MyClass::MyClass(const std::vector<std::string> &data){
for (int i = 0; i < data.size(); i += 2) {
this->parameters.insert(
std::unique_ptr<Parameter>(
static_cast<unsigned int>(std::stoi(data[i])),
std::string(data[i + 1])
)
);
}
}
Result by a compiler:
error: no matching function for call to ‘std::vector<std::tuple<unsigned int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::insert(semac::command::Parameter)’
So my question: Is there such a way to create an instance of using MyTuple = std::tuple<...>; as I tried in the code? What is the best way to do this generally?
(I'm creating the answer just to make this question answered)
As Igor Tandetnik and Some programmer dude said, the right way to do this is using std::make_unique or std::unique_ptr<Parameter>(new Parameter(static_cast<unsigned int>(std::stoi(data[i])), data[i + 1]))
The final code could look like this:
MyClass::MyClass(const std::vector<std::string> &data){
for (int i = 0; i < data.size(); i += 2) {
this->parameters.push_back(std::unique_ptr<Parameter>(new Parameter(static_cast<unsigned int>(std::stoi(data[i])), data[i + 1])));
}
}
As user6386155 metioned, it can be done using the emplace_back method (std::vector::emplace_back).
MyClass::MyClass(const std::vector<std::string> &data){
for (int i = 0; i < data.size(); i += 2) {
this->parameters.emplace_back(new Parameter(static_cast<unsigned int>(std::stoi(data[i])), data[i + 1]));
}
}
Also be careful when using the CLion IDE (2017.2.1), there is a bug
"Can't resolve constructor" when using type alias inside class
https://youtrack.jetbrains.com/issue/CPP-7536
I was very confused because of it.
Related
I'm trying to build an Rcpp interface to an existing C++ library that uses const char* for strings. I think I need to use Rcpp::List to pass some output indices, which is a ragged 2D array of strings. But I am having trouble converting this to the C++ primitives required by the external function.
#include <Rcpp.h>
// Enable C++11 via this plugin (Rcpp 0.10.3 or later)
// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::export]]
void test(Rcpp::List IndexList){
// convert list to this
const std::vector<std::vector<const char*>> Indexes;
for (int i = 0; i < IndexList.size(); i++){
Rcpp::StringVector temp = IndexList[i];
std::vector<const char*> temp2;
temp2.clear();
for (int j = 0; j < temp.size(); j++){
Rcpp::Rcout << temp[j];
temp2.push_back(temp[j]);
}
Indexes.push_back(temp2);
}
}
/*** R
test(list(c("a", "b"), c("cde")))
*/
The line Indexes.push_back(temp2); throws an error which ever way I try to build this object (which I need to pass to another function).
Line 19 passing 'const std::vector<std::vector<const char*> >' as 'this' argument of 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::vector<const char*>; _Alloc = std::allocator<std::vector<const char*> >; std::vector<_Tp, _Alloc>::value_type = std::vector<const char*>]' discards qualifiers [-fpermissive]
Solution
#include <Rcpp.h>
// Enable C++11 via this plugin (Rcpp 0.10.3 or later)
// [[Rcpp::plugins(cpp11)]]
// function that wants this data structure
void feedme(const std::vector<std::vector<const char *>> &Indexes){
Rcpp::Rcout << " feedme ";
for (unsigned i = 0; i < Indexes.size(); i++){
for (unsigned j = 0; j < Indexes[i].size(); j++){
Rcpp::Rcout << Indexes[i][j];
}
}
}
// [[Rcpp::export]]
void test(Rcpp::List IndexList){
// convert list to this
Rcpp::Rcout << " test ";
std::vector<std::vector<const char*>> Indexes;
for (int i = 0; i < IndexList.size(); i++){
Rcpp::StringVector temp = IndexList[i];
std::vector<const char*> temp2;
temp2.clear();
for (int j = 0; j < temp.size(); j++){
Rcpp::Rcout << temp[j];
temp2.push_back(temp[j]);
}
Indexes.push_back(temp2);
}
feedme(Indexes);
}
/*** R
test(list(c("a", "b"), c("cde")))
*/
You are declaring Indexes as const but try to change it later on:
const std::vector<std::vector<const char*>> Indexes;
// ^^^^^
// [...]
Indexes.push_back(temp2);
Remove the const qualifier to get the code compiled.
Maybe this helps. Here we pass from of a Rcpp::StringVector to two vectors of both const char * and char *. I was half-expecting to have to const-cast but it just built as is.
Code
#include <Rcpp.h>
void consumeConstChar(std::vector<const char*> v) {
for (auto s : v) Rcpp::Rcout << s << std::endl;
}
void consumeChar(std::vector<char*> v) {
for (auto s : v) Rcpp::Rcout << s << std::endl;
}
// [[Rcpp::export]]
void doStuff(Rcpp::StringVector x) {
std::vector<const char*> vcc;
std::vector<char*> vc;
for (int i=0; i<x.size(); i++) {
vcc.push_back(x[i]);
vc.push_back(x[i]);
}
consumeConstChar(vcc);
consumeChar(vc);
}
/*** R
x <- c("The quick", "brown", "fox", "jumped")
doStuff(x)
*/
Demo
R> Rcpp::sourceCpp("~/git/stackoverflow/58741017/answer.cpp")
R> x <- c("The quick", "brown", "fox", "jumped")
R> doStuff(x)
The quick
brown
fox
jumped
The quick
brown
fox
jumped
R>
It is kind of exasperating that std collections don't provide a functional map interface to fill a collection
std::vector< int > oldV = {1,3,5};
std::vector< int > newV = (oldV % [&](int v)-> int{ return v+1; });
newV.insert( oldV.begin(), oldV.end(), [&](int v)-> int{ return 2*v; });
Is there a simple header library that implements wrappers for functional style programming with std collections?
I don't see a way to do it such that it would apply both to things like std::vector and std::unordered_set without repeating the operator definition for each container. In the case of vector it would be like this:
#include <iostream>
#include <vector>
template <typename T, typename Lambda>
std::vector< T > operator |(const std::vector< T >& input, Lambda map)
{
std::vector< T > output;
for (const T& elem : input)
output.push_back( map(elem) );
return std::move(output);
};
int main()
{
std::vector< int > oldV = {1,3,5};
std::vector< int > newV = oldV | [&](int v) -> int { return v + 1; };
for(int i=0; i< newV.size() ; i++)
{
std::cout << newV[i] << std::endl;
}
};
For the case of std::unordered_set you would only have to replace push_back with insert
The pipe operator here has the same well known semantics as on Unix/Linux shells and some languages
You could use std::generate and std::transform to do this.
I am a lazy programmer. I want to use C++ vector to create a multidimensional array. For example, this code create a 3x2 2D array:
int nR = 3;
int nC = 2;
vector<vector<double> > array2D(nR);
for(int c = 0; c < nC; c++)
array2D.resize(nC, 0);
However, I am too lazy to
declare array2D's data type: vector<vector<double> >
C++ auto could solve this problem.
However, I am too lazy to
write loop(s) to allocate the space(s) for each object like array2D.
Writing a function could solve this problem.
However, I am too lazy to
write each function for each N-dimensional array.
write nested N-1 loops for allocating spaces.
wirte each function for each data type.
The C++11 variadic template with function recursion could solve this problem.
Is it possible ...?
This is what you want. (Tested on Microsoft Visual C++ 2013 Update 1)
#include <iostream>
#include <vector>
using namespace std;
template<class elemType> inline vector<elemType> getArrayND(int dim) {
// Allocate space and initialize all elements to 0s.
return vector<elemType>(dim, 0);
}
template<class elemType, class... Dims> inline auto getArrayND(
int dim, Dims... resDims
) -> vector<decltype(getArrayND<elemType>(resDims...))> {
// Allocate space for this dimension.
auto parent = vector<decltype(getArrayND<elemType>(resDims...))>(dim);
// Recursive to next dimension.
for (int i = 0; i < dim; i++) {
parent[i] = getArrayND<elemType>(resDims...);
}
return parent;
}
int main() {
auto test3D = getArrayND<double>(2, 3, 4);
auto test4D = getArrayND<double>(2, 3, 4, 2);
test3D[0][0][1] = 3;
test4D[1][2][3][1] = 5;
cout << test3D[0][0][1] << endl;
cout << test4D[1][2][3][1] << endl;
return 0;
}
If I declare a boost::numeric::ublas::vector aaa and later call the method aaa.erase_element(n), I get a vector with the same size, but with the n-element equal to zero.
Do you know how can I completely remove the element in order to get a lower-size vector?
I can't use std::vector unfortunately...
template<class T> void remove(vector<T> &v, uint idx)
{
assert(idx < v.size());
for (uint i = idx; i < v.size() - 1; i++) {
v[i] = v[i + 1];
}
v.resize(v.size() - 1);
}
Note: this works if T is a primitive type (int, double, etc.) or simple struct. If T is a pointer
type, or contains pointers, then you may need to look after destruction of referenced objects. Or perhaps use ptr_vector.
I'm fairly new to C++, and am trying to get the istream to work. I have a class of:
class rat
{
private:
int num;
int denom;
public:
rat();
rat(const int&, const int&);
rat(const int&);
friend ostream& operator << (ostream&, const rat&);
friend istream& operator >> (istream&, const rat&);
};
rat::rat(void)
{
num = 0;
denom = 1;
}
rat::rat(const int &n, const int &d)
{
num = n;
denom = d;
simplify();
}
rat::rat(const int &n)
{
num = n;
denom = 1;
}
ostream& operator << (ostream &os, const rat &r1)
{
os << r1.num;
os << "/";
os << r1.denom;
return os;
}
istream& operator >> (istream &is, const rat &r1)
{
is >> r1.num;
is >> r1.denom;
return is;
}
I also have a .cpp of:
#include <iostream>
#include <conio.h>
using namespace std;
#include "Rats.h"
void main()
{
rat r1(3,4), r2(2,3), r3;
system("cls");
cout << "Please enter a rational number: ";
cin >> r3;
}
My problem occurs whenever it comes across the "is >> r1.num;" line. It gives me the error: Unhandled exception at 0x772d15de in RatClass.exe: 0xC00000FD: Stack overflow.
Again, I'm fairly new, so have not learned what the possible cause could be yet. Any help is appreciated.
Looks like it might be the fact that you're accepting const rat &r1 but by sending data from the istream you would be changing r1. You can't change constants. Not sure if this is the issue but that's the first obvious thing that came to mind.
Try this:
istream& operator >> (istream &is, rat &r1)
{
is >> r1.num;
is >> r1.denom;
return is;
}
Don't forget to change your definition in the class:
friend istream& operator >> (istream&, rat&);