I'm fairly new to C++, and I wanted to test what I know about it by implementing a mediocre List class.
List.hpp:
#ifndef LIST_HPP
#define LIST_HPP
// Only supports int lists up to 100 items for now.
class List
{
public:
List(int arr[], int length);
void append(int item);
void print();
void remove();
int len();
List operator+(List obj);
protected:
private:
int *list = new int[100];
int size = 0;
};
#endif
List.cpp:
#include <iostream>
#include "List.hpp"
List::List(int arr[], int length)
: size(length)
{
for (int i = 0; i < length; i++)
{
list[i] = arr[i];
}
}
void List::append(int item)
{
list[size] = item;
size++;
}
void List::print()
{
for (int i = 0; i < size; i++)
{
if (i == 0)
{
std::cout << '[';
}
std::cout << list[i];
if (i == size - 1)
{
std::cout << ']' << std::endl;
}
else
{
std::cout << ", ";
}
}
}
void List::remove()
{
if (size == 0) {
std::cout << "Error: list is empty" << std::endl;
return;
}
else {
for (int i = 0; i < size - 1; i++) {
list[i] = list[i + 1];
}
size--;
}
}
int List::len()
{
return size;
}
List List::operator+(List obj)
{
List res({}, 0);
for (int i = 0; i < this->size; i++)
res.append((this->list)[i]);
for (int i = 0; i < obj.size; i++)
res.append((obj.list)[i]);
res.size = this->size + obj.size;
return res;
}
However, upon initializing List mylist({1, 2, 3}, 3);, the compiler says,
main.cpp: In function 'int main()':
main.cpp:9:29: error: no matching function for call to 'List::List(<brace-enclosed initializer list>, int)'
List mylist({1, 2, 3}, 3);
^
In file included from main.cpp:3:0:
List.hpp:9:9: note: candidate: List::List(int*, int)
List(int arr[], int length);
^~~~
List.hpp:9:9: note: no known conversion for argument 1 from '<brace-enclosed initializer list>' to 'int*'
List.hpp:6:7: note: candidate: constexpr List::List(const List&)
class List
^~~~
List.hpp:6:7: note: candidate expects 1 argument, 2 provided
List.hpp:6:7: note: candidate: constexpr List::List(List&&)
List.hpp:6:7: note: candidate expects 1 argument, 2 provided
But when I intialize mylist using
int myarr[3] = {1, 2, 3};
List mylist(myarr, 3);
it works perfectly. Why is this so?
In List mylist({1, 2, 3}, 3);, {1, 2, 3} isn't an array, its a std::initializer_list.
Related
I am implementing a parallel accumulator class in C++. The implementation of the class is as follows:
#include <iostream>
#include <thread>
#include <cstring>
#include "cblas.h"
class ParallelAccumulator {
public:
int num_contributions;
double** contributions;
int* is_contributing;
int num_elements;
ParallelAccumulator(int num_contributions, int num_elements) {
this->num_contributions = num_contributions;
this->num_elements = num_elements;
contributions = new double*[num_contributions];
is_contributing = new int[num_contributions];
for (int i = 0; i < num_contributions; i++) {
contributions[i] = new double[num_elements];
is_contributing[i] = 0;
}
}
void reset() {
for (int i = 0; i < num_contributions; i++) {
is_contributing[i] = 0;
}
}
void zero_contributions() {
for (int i = 0; i < num_contributions; i++) {
memset(contributions[i], 0, num_elements * sizeof(double));
}
}
int check_out_contribution() {
for (int i = 0; i < num_contributions; i++) {
if (is_contributing[i] == 0) {
is_contributing[i] = 1;
return i;
}
}
return -1;
}
void check_in_contribution(int contrib_index) {
is_contributing[contrib_index] = 0;
}
void reduce(double* output) {
for (int i = 0; i < num_contributions; i++) {
if (is_contributing[i] == 1) {
cblas_daxpy(num_elements, 1.0, contributions[i], 1, output, 1);
}
}
}
~ParallelAccumulator() {
for (int i = 0; i < num_contributions; i++) {
delete[] contributions[i];
}
delete[] contributions;
delete[] is_contributing;
}
};
However, I am having compilation issues when I create the threads to test the class as follows:
void test_function(ParallelAccumulator& accumulator, double* output, int id) {
int contrib_index = accumulator.check_out_contribution();
if (contrib_index == -1) {
std::cout << "Error: no available contrib arrays" << std::endl;
return;
}
double* contrib = accumulator.contributions[contrib_index];
for (int i = 0; i < accumulator.num_elements; i++) {
contrib[i] = id;
}
accumulator.check_in_contribution(contrib_index);
}
int main() {
int num_contributions = 4;
int num_elements = 10;
double output[num_elements];
ParallelAccumulator accumulator(num_contributions, num_elements);
/* problematic code start here */
std::thread t1(test_function, std::ref(accumulator), output, 1);
std::thread t2(test_function, std::ref(accumulator), output, 2);
std::thread t3(test_function, std::ref(accumulator), output, 3);
std::thread t4(test_function, std::ref(accumulator), output, 4);
/* problematic code end here */
t1.join();
t2.join();
t3.join();
t4.join();
accumulator.reduce(output);
for (int i = 0; i < num_elements; i++) {
std::cout << output[i] << " ";
}
std::cout << std::endl;
return 0;
}
The compilation errors are:
parallel_accumulator.cpp:87:67: error: no matching function for call to 'std::thread::thread(void (&)(ParallelAccumulator&, double*, int), std::reference_wrapper<ParallelAccumulator>, double [num_elements], int)' 87 | std::thread t1(test_function, std::ref(accumulator), output, 1);
| ^ In file included from /usr/local/Cellar/gcc/11.3.0_2/include/c++/11/thread:43,
from parallel_accumulator.cpp:2: /usr/local/Cellar/gcc/11.3.0_2/include/c++/11/bits/std_thread.h:127:7: note: candidate: 'template<class _Callable, class ... _Args, class> std::thread::thread(_Callable&&, _Args&& ...)' 127 | thread(_Callable&& __f, _Args&&... __args)
| ^~~~~~ /usr/local/Cellar/gcc/11.3.0_2/include/c++/11/bits/std_thread.h:127:7: note: template argument deduction/substitution failed: parallel_accumulator.cpp:87:67: note: variable-sized array type 'double (&)[num_elements]' is not a valid template argument 87 | std::thread t1(test_function, std::ref(accumulator), output, 1);
| ^ In file included from /usr/local/Cellar/gcc/11.3.0_2/include/c++/11/thread:43,
from parallel_accumulator.cpp:2: /usr/local/Cellar/gcc/11.3.0_2/include/c++/11/bits/std_thread.h:157:5: note: candidate: 'std::thread::thread(std::thread&&)' 157 | thread(thread&& __t) noexcept
| ^~~~~~ /usr/local/Cellar/gcc/11.3.0_2/include/c++/11/bits/std_thread.h:157:5: note: candidate expects 1 argument, 4 provided /usr/local/Cellar/gcc/11.3.0_2/include/c++/11/bits/std_thread.h:121:5: note: candidate: 'std::thread::thread()' 121 | thread() noexcept
= default;
| ^~~~~~
What is the proper syntax to fix the error? What modifications can I make to this implementation to make it work properly and have as much flexibility as possible?
Thanks a lot to all the participants in the discussion above, in particular to #doron. The code with the correct syntax is as follows:
constexpr int num_elements = 10;
std::thread t1(test_function, std::ref(accumulator), &output[0], 1);
std::thread t2(test_function, std::ref(accumulator), &output[0], 2);
std::thread t3(test_function, std::ref(accumulator), &output[0], 3);
std::thread t4(test_function, std::ref(accumulator), &output[0], 4);
There are several ways to call std::thread::thread(), when in doubt, use the simplest one using a lambda..
This sure isn't the most pedantic answer, but it does not penalise performance and always works.
// quick and efficient
std::thread t1([&]() { test_function(accumulator), &output[0], 1); });
// etc...
// If you do not like vague lambda captures
std::thread t1([&accumulator, &output]() { test_function(accumulator), &output[0], 1); });
// etc...
I am trying to create a template which will add an element to the end of an array (after resizing). I want to specialize it so that if the type is char*, it will include a null byte at the end.
Here is my main:
int main()
{
int* arrI = nullptr;
arrI = insertAtend(arrI, 0, 1); //1
std::cout << arrI[0];
delete[] arrI;
char* arrC = nullptr;
arrC = insertAtend(arrC, 0, 'a'); //a
std::cout << arrC;
delete[] arrC;
return 0;
}
And here are the templates:
template<typename T>
T* insertAtend(T* arr, int size, const T toAdd)
{
T* temp = new T[++size];
if (arr)
{
for (int i = 0; i < size; i++)
{
temp[i] = arr[i];
}
delete[] arr;
}
arr = new T[size + 1];
if (temp)
{
for (int i = 0; i < size; i++)
{
arr[i] = temp[i];
}
}
delete[] temp;
arr[size - 1] = toAdd;
return arr;
}
template<>
char* insertAtend<char*>(char* a, int s, const char* d)
{
return a;
}
Obviously without logic, but I am getting an error:
C2912 "Error C2912 explicit specialization 'char *insertAtend<char>(char *,int,const char *)' is not a specialization of a function template"
You're simply confusing the base type (char) with the pointer type (char *).
Change your specialization to this:
template<>
char* insertAtend<char>(char* a, int s, const char d)
{
return a;
}
Recently, I am learning C++.
I am trying to print the adjacencyNodes but it shows error and I can't understand why
Here is the code
Class for List
#include <iostream>
using namespace std;
class List{
int list[100];
int size = 0;
public:
void add(int a){
list[size] = a;
size++;
}
int get(int i){
return list[i];
}
};
Class for Graph
class Graph{
bool isDirected;
int noNodes;
int adjacencyMatrix[100][100];
int noEdges = 0;
public:
Graph(bool isDirected, int noNodes){
this->isDirected = isDirected;
this->noNodes = noNodes;
for(int i=0;i<noNodes;i++)
for(int j=0;j<noNodes;j++)
adjacencyMatrix[i][j]=0;
}
void addEdge(int a, int b){
adjacencyMatrix[a][b] = 1;
if (!isDirected) adjacencyMatrix[b][a] = 1;
noEdges++;
}
bool isEdge(int a, int b){
if(adjacencyMatrix[a][b] == 1) return 1;
else return 0;
}
int inDegree(int a){
int indegree=0;
for(int m=0;m<noNodes;m++){
if(adjacencyMatrix[m][a] == 1){
indegree++;
}
}
return indegree;
}
int outDegree(int a){
int outdegree=0;
for(int n =0;n < noNodes;n++){
if(adjacencyMatrix[a][n] == 1){
outdegree++;
}
}
return outdegree;
}
List adjacencyNodes(int a){
List adj;
int ind = 0;
for(int i=0; i<noNodes; i++){
if(adjacencyMatrix[a][i] == 1){
adj.add(i);
ind++;
}
}
return adj;
}
};
int main(){
int n, e, a, b, x;
//input number of nodes and number of Edges
cin>>n>>e;
//create a directed graph
Graph G(1,n);
for(int i=0;i<e;i++){
cin>>a>>b;
G.addEdge(a,b);
}
//input another number x
cin>>x;
//print the degree of x
cout<<"Indegree\n"<<G.inDegree(x);
cout<<"\nOutdegree\n"<<G.outDegree(x);
// print all the adjacent nodes of x
// List L = G.adjacencyNodes(x); for()
cout<<"\n"<<G.adjacencyNodes(x);
return 0;
}
I'm getting the error here
cout<<"\n"<<G.adjacencyNodes(x);
error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream}' and 'List')
Is there any way to print it out?
You will need to overload << operator in order to use it. As you said you are learning C++ newly, so I would suggest to add a method show() to List Class to show its contents.
class List
{
int list[100];
int size = 0;
public:
void add(int a)
{
list[size] = a;
size++;
}
int get(int i)
{
return list[i];
}
void show()
{
for(int i=0;i<size;i++)
cout<<list[i];
cout<<endl;
}
};
And then you just need a call to that Method like
G.adjacencyNodes(x).show();
And you are done!
I am trying to run a code that defines objects that are a collection of English letters.
I dont know why it does not compile.
I have tried to change from int to const int but it is not the case,
and also added the disable 4996 message but it didnt help.
#include <iostream>
using namespace std;
class CharSet
{
int size;
char* pSet;
public:
// -----------------------------------
CharSet(int const size, char* set)
{
this->size = size;
pSet = new char[strlen(set) + 1];
strcpy(pSet, set);
}
// -----------------------------------
~CharSet()
{
delete[] pSet;
}
// -----------------------------------
CharSet operator*(const CharSet & other)
{
int maxSize = 0;
if (this->size >= other.size)
maxSize = this->size;
else
maxSize = other.size;
char * ret = new char[maxSize + 1];
char temp;
int index = 0;
for (int i = 0; i < this->size; i++)
{
temp = this->pSet[i];
for (int j = 0; j < other.size; j++)
{
if (other.pSet[j] == temp)
{
ret[index] = temp;
index++;
}
}
}
ret[index] = '\0';
return CharSet(maxSize, ret);
}
// -----------------------------------
bool operator()(char check)
{
bool flag = false;
for (int i = 0; i < this->size; i++)
{
if (pSet[i] == check)
flag = true;
}
return flag;
}
// -----------------------------------
friend ostream& operator<<(ostream& os, const CharSet& s)
{
os << s.pSet;
return os;
}
// -----------------------------------
};
int main()
{
CharSet s1(4, "DAQP"), s2(3, "AXZ");
cout << s1 * s2 << endl;
if (s1('Q') == true)
cout << "The element is member of the set" << endl;
else
cout << "The element is not member of the set" << endl;
return 0;
}
errors:
E0289 no instance of constructor "CharSet::CharSet" matches the argument
E0289 no instance of constructor "CharSet::CharSet" matches the argument list
C4996 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
C2664 'CharSet::CharSet(const CharSet &)': cannot convert argument 2 from
C2664 'CharSet::CharSet(const CharSet &)': cannot convert argument 2 from 'const char [4]' to 'char *'
you need a const char* in your constructor:
CharSet(int const size, const char* set)
Thanks to
#holy black cat
"DAQP" is a const char[] which you didn't provide a constructor for that(the array will implicitly convert to pointer).
A better way is using std::string:
class CharSet
{
std::string pSet;
public:
// -----------------------------------
CharSet(std::string set) : pSet(set)
{
}
// -----------------------------------
~CharSet()
{
}
// -----------------------------------
CharSet operator*(const CharSet & other)
{
int maxSize = 0;
std::string ret;
char temp;
int index = 0;
for (int i = 0; i < pSet.size(); i++)
{
temp = pSet[i];
for (int j = 0; j < other.pSet.size(); j++)
{
if (other.pSet[j] == temp)
{
ret += temp;
index++;
}
}
}
return CharSet(ret);
}
// the rest of members ...
//
};
full code at godblot
Compilation error is:
'initializing': cannot convert from 'int' to 'Money'
File: genericarray.h
Line: 13
This is my main function
int main()
{
genericArray<Money>m3(5);
Money d(-1, 89);
Money a(10, 5);
Money b(10, 5);
Money c(43, 7);
Money k(50, 6);
Money m(10, 20);
Money bonus(5, 0);
m3.elements[0] = a;
m3.elements[1] = b;
m3.elements[2] = c;
m3.elements[3] = k;
m3.elements[4] = m;
m3.total = m3.sum();
m2.total = m2.sum();
m1.total = m1.sum();
return 0;
}
This is my Assignment operator overloading of Money class and Money class itself
class Money
{
private:
int lira;
int kurus;
public:
Money() { lira = 0; kurus = 0; }
Money(int a, int b);
~Money() {}
void operator=(const Money& money2) { this->lira = money2.lira; this->kurus = money2.kurus; }
void operator=(int l) { this->lira = l; this->kurus = 0; }
This is my genericArray class with sum() function
template <class Type>
class genericArray
{
private:
int size;
public:
Type* elements;
Type total;
Type sum()
{
Type sumAll = 0;
for (int i = 0; i < size; i++)
{
sumAll += elements[i];
}
if (sumAll > 100)
sumAll += 5;
return sumAll;
}
genericArray() { elements = NULL; size = 0; }
genericArray(int arrSize) { elements = new Type[arrSize]; size = arrSize; }
~genericArray() { delete[] elements; }
};
Writing a new constructor with a single int parameter solved the problem:
Money(const int a)
{
if (a < 0) throw "The amount of money can not be below zero!";
this->lira = a;
this->kurus = 0;
}
The point is that
Type sumAll = 0;
calls only the constructor which takes only 1 int instead of calling the default constructor and the assignment operator.