I am trying to create a custom channel in System C. Channel data structure is like following
struct Command {
int cmdType;
int lba;
double timestamp;
int size;
Command() { }
Command(const int c, const int l, const double ts, const int sz) {
make(c, l, ts, sz);
}
void make(const int c, const int l, const double ts, const int sz) {
cmdType = c;
lba = l;
timestamp = ts;
size = sz;
}
inline bool operator ==(const Command & command) const {
return (command.cmdType == cmdType && command.lba == lba
&& command.timestamp == timestamp
&& command.size == size); }
};
ostream and trace functions for this channel are defined as follows
inline ostream & operator <<(ostream & os, const Command command)
{
os << "CmdType " << command.cmdType << endl;
os << "Lba " << command.lba << endl;
os << "Time " << command.timestamp <<endl;
os << "Data " << command.size << endl;
return os;
}
inline void sc_trace(sc_trace_file * &tf, const Command & command, string &name)
{
sc_trace(tf, command.cmdType, name + ".cmdType");
sc_trace(tf, command.lba, name + ".lba");
sc_trace(tf, command.timestamp, name + ".timestamp");
sc_trace(tf, command.size, name + ".size");
}
however I am getting compile error
the error message is very long, however here is the last part
/home/user/user/systemc-2.3.1//include/sysc/tracing/sc_trace.h:312:6: note: candidate expects 4 arguments, 3 provided
/home/user/user/systemc-2.3.1//include/sysc/tracing/sc_trace.h:317:6: note: void sc_core::sc_trace(sc_core::sc_trace_file*, const sc_core::sc_signal_in_if<short int>&, const string&, int)
void sc_trace( sc_trace_file* tf,
^
/home/user/user/systemc-2.3.1//include/sysc/tracing/sc_trace.h:317:6: note: candidate expects 4 arguments, 3 provided
/home/user/user/systemc-2.3.1//include/sysc/tracing/sc_trace.h:322:6: note: void sc_core::sc_trace(sc_core::sc_trace_file*, const sc_core::sc_signal_in_if<int>&, const string&, int)
void sc_trace( sc_trace_file* tf,
^
/home/user/user/systemc-2.3.1//include/sysc/tracing/sc_trace.h:322:6: note: candidate expects 4 arguments, 3 provided
/home/user/user/systemc-2.3.1//include/sysc/tracing/sc_trace.h:327:6: note: void sc_core::sc_trace(sc_core::sc_trace_file*, const sc_core::sc_signal_in_if<long int>&, const string&, int)
void sc_trace( sc_trace_file* tf,
^
/home/user/user/systemc-2.3.1//include/sysc/tracing/sc_trace.h:327:6: note: candidate expects 4 arguments, 3 provided
/home/user/user/systemc-2.3.1//include/sysc/tracing/sc_trace.h:343:1: note: void sc_core::sc_trace(sc_core::sc_trace_file*, const unsigned int&, const string&, const char**)
sc_trace( sc_trace_file* tf,
^
/home/user/user/systemc-2.3.1//include/sysc/tracing/sc_trace.h:343:1: note: candidate expects 4 arguments, 3 provided
/home/user/user/systemc-2.3.1//include/sysc/tracing/sc_trace.h:351:13: note: void sc_core::sc_trace(sc_core::sc_trace_file*, const void*, const string&)
extern void sc_trace( sc_trace_file* tf,
^
/home/user/user/systemc-2.3.1//include/sysc/tracing/sc_trace.h:351:13: note: no known conversion for argument 2 from ‘const Command’ to ‘const void*’
In file included from /home/user/user/systemc-2.3.1//include/sysc/communication/sc_clock_ports.h:31:0,
from /home/user/user/systemc-2.3.1//include/systemc:79,
from /home/user/user/systemc-2.3.1//include/systemc.h:208,
from initiator.h:5,
from initiator.cpp:1:
/home/user/user/systemc-2.3.1//include/sysc/communication/sc_signal_ports.h:1808:1: note: template<class T> void sc_core::sc_trace(sc_core::sc_trace_file*, const sc_core::sc_inout<T>&, const string&)
sc_trace( sc_trace_file* tf, const sc_inout<T>& port,
^
/home/user/user/systemc-2.3.1//include/sysc/communication/sc_signal_ports.h:1808:1: note: template argument deduction/substitution failed:
/home/user/user/systemc-2.3.1//include/sysc/communication/sc_signal_ports.h:1165:46: note: ‘const Command’ is not derived from ‘const sc_core::sc_inout<T>’
sc_trace( p->tf, iface->read(), p->name );
^
/home/user/user/systemc-2.3.1//include/sysc/communication/sc_signal_ports.h:1791:1: note: template<class T> void sc_core::sc_trace(sc_core::sc_trace_file*, const sc_core::sc_in<T>&, const string&)
sc_trace(sc_trace_file* tf, const sc_in<T>& port, const std::string& name)
^
/home/user/user/systemc-2.3.1//include/sysc/communication/sc_signal_ports.h:1791:1: note: template argument deduction/substitution failed:
/home/user/user/systemc-2.3.1//include/sysc/communication/sc_signal_ports.h:1165:46: note: ‘const Command’ is not derived from ‘const sc_core::sc_in<T>’
sc_trace( p->tf, iface->read(), p->name );
^
appreciate help regarding how to fix this compile issue
here is simple version of the code --- file main.c
#include <stdio.h>
#include <csignal>
#include "systemc.h"
#include "producer.h"
#include "consumer.h"
#include "stdtype.h"
#include <iomanip>
#include <sstream>
using namespace std;
inline ostream & operator <<(ostream & os, const Command command)
{
os << "CmdType " << command.cmdType << endl;
return os;
}
inline void sc_trace(sc_trace_file * tf, const Command & command, const string & name)
{
int* cmdType = (int*) &(command.cmdType);
sc_trace(tf, cmdType, name + ".cmdType");
}
int sc_main(int arg_num, char *arg_vet[])
{
sc_clock clock("clock", 100, SC_PS);
sc_signal <bool> reset;
sc_signal <Command> cmd;
Producer *prd;
prd = new Producer("Producer");
prd->clock(clock);
prd->reset(reset);
prd->cmd_tx(cmd);
Consumer *con;
con = new Consumer("Consumer");
con->clock(clock);
con->reset(reset);
con->cmd_rx(cmd);
sc_trace_file *tf = NULL;
tf = sc_create_vcd_trace_file("trace");
sc_trace(tf, reset, "reset");
sc_trace(tf, clock, "clock");
reset.write(1);
sc_start(100, SC_NS);
reset.write(0);
sc_start(100, SC_NS);
sc_close_vcd_trace_file(tf);
return 0;
}
file consumer.h
#ifndef __CONSUMER_H__
#define __CONSUMER_H__
#include <queue>
#include <systemc.h>
#include "stdtype.h"
using namespace std;
SC_MODULE(Consumer)
{
sc_in_clk clock;
sc_in <bool> reset;
sc_in <Command> cmd_rx;
void ConsumerProcess();
SC_CTOR(Consumer) {
SC_METHOD(ConsumerProcess);
sensitive << reset;
sensitive << clock.pos();
}
};
#endif
file producer.h
#ifndef __PRODUCER_H__
#define __PRODUCER_H__
#include <queue>
#include <systemc.h>
#include "stdtype.h"
using namespace std;
SC_MODULE(Producer)
{
sc_in_clk clock;
sc_in <bool> reset;
sc_out <Command> cmd_tx;
void ProducerProcess();
SC_CTOR(Producer) {
SC_METHOD(ProducerProcess);
sensitive << reset;
sensitive << clock.pos();
}
};
#endif
file consumer.cpp
#include "consumer.h"
void Consumer:: ConsumerProcess(void)
{
cout << "con" << endl;
}
file producer.cpp
#include "producer.h"
void Producer:: ProducerProcess(void)
{
cout << "prd" << endl;
}
and file stdtype.h
#ifndef __STDTYPE_H__
#define __STDTYPE_H__
#include <queue>
#include <systemc.h>
struct Command {
int cmdType;
inline bool operator ==(const Command & command) const {
return (command.cmdType == cmdType); }
};
#endif
to compile above code here is the command line:
g++ -I. -I$SYSTEMC_HOME/include -L. -L$SYSTEMC_HOME/lib-linux64
-Wl,-rpath=$SYSTEMC_HOME/lib-linux64 -I/usr/local/include -L/usr/local/lib -lyaml-cpp -o main main.cpp producer.cpp consumer.cpp -lsystemc -lm
Are you sure that sc_trace function is right?
In order to be successful of your call, overloading function of two types is necessary at least. of course, I didn't think that implicit conversion class.
Anyway, two functions are as below:
sc_trace(sc_trace_file, int, string)
sc_trace(sc_trace_file, double, string)
`
inline void sc_trace(sc_trace_file * &tf, const Command & command, string &name)
{
sc_trace(tf, command.cmdType, name + ".cmdType"); // 1
sc_trace(tf, command.lba, name + ".lba"); // 1
sc_trace(tf, command.timestamp, name + ".timestamp"); // 2
sc_trace(tf, command.size, name + ".size"); // 1
}
found the fix!!!
changed stdtype.h as follows
#ifndef __STDTYPE_H__
#define __STDTYPE_H__
#include <queue>
#include <systemc.h>
#include <iomanip>
#include <sstream>
#include <map>
#include <utility>
#include <vector>
#include <string>
using namespace std;
struct Command {
int cmdType;
inline bool operator ==(const Command & command) const {
return (command.cmdType == cmdType); }
};
inline ostream & operator <<(ostream & os, const Command & command)
{
os << "CmdType " << command.cmdType << endl;
return os;
}
inline void sc_trace(sc_trace_file * tf, const Command & command, const string & name)
{
sc_trace(tf, command.cmdType, name + ".cmdType");
}
#endif
and removed these functions from main.cpp, this fixed the issue and i can trace the channel in vcd file, also added other code to communicate through the channel
Related
I'm currently trying to understand the basic concepts of operator overloading in C++. Therefore, I created a class wheel that is able to read from a stream by overloading the stream extraction operator >>.
wheel.h
#ifndef WHEEL_H
#define WHEEL_H
#include <cassert>
#include <ostream>
#include <string>
class wheel final {
float rimDiameter;
int productionYear;
std::string velocityIndex = "N/A";
std::string manufacturer = "N/A";
public:
wheel() = default;
wheel( float rimDiameter,
int productionYear,
std::string velocityIndex,
std::string manufacturer
) : rimDiameter{rimDiameter},
productionYear{productionYear},
velocityIndex{velocityIndex},
manufacturer{manufacturer}
{}
~wheel() = default;
friend
auto operator<<(std::ostream &os, const wheel &self) -> std::ostream &;
friend
auto operator>>(std::istream &is, wheel &self) -> std::istream &;
};
#endif
wheel.cpp
#include "wheel.h"
auto operator<<(std::ostream &os, const wheel &self) -> std::ostream & {
return os << " WHEEL" << std::endl
<< " =============================" << std::endl
<< " Rim Diameter: " << self.rimDiameter << "\"" << std::endl
<< " Year of Production: " << self.productionYear << std::endl
<< " Velocity Index: " << self.velocityIndex << std::endl
<< " Manufacutrer: " << self.manufacturer << std::endl;
}
auto operator>>(std::istream &is, wheel &self) -> std::istream & {
char c[3];
is >>
self.rimDiameter >> c[0] >>
self.productionYear >> c[1] >>
self.velocityIndex >> c[2] >>
self.manufacturer;
assert(c[0] == ';' && c[1] == ';' && c[2] == ';');
return is;
}
main.cpp
#include <iostream>
#include "wheel.h"
int main(void) {
wheel w;
std::cin >> w;
std::cout << w;
return 0;
}
To me, it all looks fine, but somehow I keep getting an error telling me that there is no match for 'operator>>' (operand types are 'std::istream {aka std::basic_istream<char>}' and 'float'):
$ make
g++-7 -g -std=c++17 -Wall -Wextra -Wconversion -Wpedantic -c main.cpp
g++-7 -g -std=c++17 -Wall -Wextra -Wconversion -Wpedantic -c wheel.cpp
wheel.cpp: In function 'std::istream& operator>>(std::istream&, wheel&)':
wheel.cpp:16:8: error: no match for 'operator>>' (operand types are 'std::istream {aka std::basic_istream<char>}' and 'float')
is >>
~~~^~
self.rimDiameter >> c[0] >>
~~~~~~~~~~~~~~~~
wheel.cpp:13:6: note: candidate: std::istream& operator>>(std::istream&, wheel&)
auto operator>>(std::istream &is, wheel &self) -> std::istream & {
^~~~~~~~
wheel.cpp:13:6: note: no known conversion for argument 2 from 'float' to 'wheel&'
In file included from /usr/local/Cellar/gcc/7.2.0/include/c++/7.2.0/string:53:0,
from /usr/local/Cellar/gcc/7.2.0/include/c++/7.2.0/bits/locale_classes.h:40,
from /usr/local/Cellar/gcc/7.2.0/include/c++/7.2.0/bits/ios_base.h:41,
from /usr/local/Cellar/gcc/7.2.0/include/c++/7.2.0/ios:42,
from /usr/local/Cellar/gcc/7.2.0/include/c++/7.2.0/ostream:38,
from wheel.h:5,
from wheel.cpp:1:
/usr/local/Cellar/gcc/7.2.0/include/c++/7.2.0/bits/basic_string.tcc:1465:5: note: candidate: template<class _CharT, class _Traits, class _Alloc> std::basic_istream<_CharT, _Traits>& std::operator>>(std::basic_istream<_CharT, _Traits>&, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&)
operator>>(basic_istream<_CharT, _Traits>& __in,
^~~~~~~~
/usr/local/Cellar/gcc/7.2.0/include/c++/7.2.0/bits/basic_string.tcc:1465:5: note: template argument deduction/substitution failed:
wheel.cpp:17:14: note: mismatched types 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>' and 'float'
self.rimDiameter >> c[0] >>
^~~~~~~~~~~
make: *** [wheel.o] Error 1
What am I missing here?
You need to include iostream for input and output like this #include <iostream> and you'll avoid the error.
When outputting, it's the class over which the << operators are defined you always use ostream, but you forgot the case of inputting for >>.
#ifndef WHEEL_H
#define WHEEL_H
#include <cassert>
#include <iostream>
#include <string>
class wheel final {
float rimDiameter;
int productionYear;
std::string velocityIndex = "N/A";
std::string manufacturer = "N/A";
public:
wheel() = default;
wheel( float rimDiameter,
int productionYear,
std::string velocityIndex,
std::string manufacturer
) : rimDiameter{rimDiameter},
productionYear{productionYear},
velocityIndex{velocityIndex},
manufacturer{manufacturer}
{}
~wheel() = default;
friend
auto operator<<(std::ostream &os, const wheel &self) -> std::ostream &;
friend
auto operator >> (std::istream &is, wheel &self) -> std::istream &;
};
#endif /* wheel_hpp */
As #Ext3h pointed out, I am missing the respective include for istream.
Adding #include <istream> to wheel.h resolves the problem.
Thank you very much for you help, would have taken me forever to figure out the issue!
First: I have tried reading and modifying my code based off no less than 7 other similar questions. At best, the other options trigger an avalanche of errors. With my current code, I'm down to a single error.
Putting it inside the class and using "friend" doesn't work, and using ostream& operator<< (ostream &out, const Fraction &rhs) makes a whole lot more errors.
The frustrating thing is that in c9.io this code works, but not on Netbeans.
In my main.cpp:
#include <iostream>
#include "fraction.h"
using namespace std;
int main() {
Fraction f(3, 4);
cout << f;
return 0;
}
In fraction.h:
#ifndef FRACTION_H
#define FRACTION_H
class Fraction{
public:
//constructor defs
//accessors
//modifiers/mutators
void setNumer(int newNum);
void setDenom(int newDenom);
void reduce();
private:
//instance variables
int numer;
int denom;
//helper functions
int gcd(int a, int b);
};
#endif /* FRACTION_H */
And in fraction.cpp:
#include "fraction.h"
#include <cmath>
#include <iostream>
using namespace std;
//code for constructors
//accessors
int Fraction::getNumer(){
return numer;
}
int Fraction::getDenom(){
return denom;
}
//modifiers/mutators
//other operator definitions
ostream& operator<< (ostream &out, Fraction &rhs){
if(rhs.getNumer() == 0){
out << 0;
} else if(rhs.getNumer() == rhs.getDenom()){
out << 1;
} else {
rhs.reduce();
out << rhs.getNumer() << "/" << rhs.getDenom();
}
}
The output is:
g++ -c -g -std=c++11 -MMD -MP -MF "build/Debug/GNU-Linux/main.o.d" -o build/Debug/GNU-Linux/main.o main.cpp
main.cpp: In function ‘int main()’:
main.cpp:6:13: error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
cout << f;
^
In file included from /usr/include/c++/4.8/iostream:39:0,
from main.cpp:1:
/usr/include/c++/4.8/ostream:602:5: error: initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = Fraction]’
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
^
There is no knowledge of the operator<< function that is defined in Fraction.cpp in main.cpp Hence, the line
cout << f;
is a problem.
Add the declaration of the function in the .h file.
#ifndef FRACTION_H
#define FRACTION_H
#include <iostream>
class Fraction{
public:
//constructor defs
//accessors
//modifiers/mutators
void setNumer(int newNum);
void setDenom(int newDenom);
void reduce();
private:
//instance variables
int numer;
int denom;
//helper functions
int gcd(int a, int b);
};
std::ostream& operator<< (std::ostream &out, Fraction const& rhs);
// ^^^^ Using const&, not just Fraction&
#endif /* FRACTION
So the answer was partly what #r-sahu said:
I had to set getNumer() and getDenom() as const member functions BUT I could only get the errors to go away by NOT using const& in the function definition.
Good:
std::ostream& operator<< (std::ostream &out, Fraction rhs);
Not good:
std::ostream& operator<< (std::ostream &out, Fraction const& rhs);
It now compiles and runs. any insight on why making the member functions const but not passing the Fraction as const makes it work? I stumbled on this solution by accident and don't understand it.
I am trying run the following program, But it generates compilation error:
#ifndef TEMPLATE_SUM_H_
#define TEMPLATE_SUM_H_
template<typename T>
class sum
{
public:
sum() {
val_1 = 0;
val_2 = 0;
}
sum(T a, T b) {
val_1 = a;
val_2 = b;
}
friend std::ostream& operator<<(std::ostream &, const sum<> &);
private:
T val_1, val_2;
T result() const;
};
#endif
Source file:
include <iostream>
#include "inc/sum.h"
template<typename T>
T sum<T>::result() const {
return (val_1 + val_2);
}
template<typename T>
std::ostream& operator<<(std::ostream& os, const sum<T>& obj) {
//std::ostream& operator<<(std::ostream& os, sum<T>& obj) {
os << obj.result();
return os;
}
int main()
{
sum<int> int_obj(15, 15);
sum<float> float_obj(5.2, 3.5);
std::cout << "result of int = " << int_obj << std::endl;
std::cout << "result of float = " << float_obj << std::endl;
return 0;
}
Compiling with g++ (4.4.3) it generates following error:
In file included from template.cpp:2:
inc/sum.h:18: error: wrong number of template arguments (0, should be 1)
inc/sum.h:5: error: provided for ‘template<class T> class sum’
template.cpp: In function ‘std::ostream& operator<<(std::ostream&, const sum<T>&) [with T = int]’:
template.cpp:20: instantiated from here
template.cpp:5: error: ‘T sum<T>::result() const [with T = int]’ is private
template.cpp:12: error: within this context
template.cpp: In function ‘std::ostream& operator<<(std::ostream&, const sum<T>&) [with T = float]’:
template.cpp:21: instantiated from here
template.cpp:5: error: ‘T sum<T>::result() const [with T = float]’ is private
template.cpp:12: error: within this context
1) Can Anyone please help me in identifying the error ?
Also Please suggest some links where I can find brief absolute details on how to use templates in c++.
2) I read that templatized func/classes declared in header file, and defined separately are prone to linking error. Can anyone explain/elaborate this ?
Is there any possibility of linking error in above example ?
The statement is as below:
"If a template or inline function is declared in a .h file, define it in that same file. The definitions of these constructs must be included into every .cpp file that uses them, or the program may fail to link in some build configurations."
This example can be done in some more easy way, without using overloaded operator etc. But I am trying to learn/practising templates and experimenting some features.
You need to have a separate template definition for the friend function declaration:
template<typename U>
friend std::ostream& operator<<(std::ostream &, const sum<U> &);
friend declarations do not inherit the template parameters of the enclosing class.
A simple sample source, to get started;
Calculator.h
#ifndef CALCULATOR_H
#define CALCULATOR_H
template <class TYPE>
class Calculator{
public:
Calculator();
TYPE Sum(TYPE param1, TYPE param2);
};
/**
* To avoid template related compilation error
* when templates are used in header and source files
*
* This class file has been removed from the project-source file.
* However, is present in the project folder
* Gets compiled with the header-file (being included)
*/
#include "Calculator.cpp"
#endif
Calculator.cpp
#include <iostream>
using namespace std;
#include "Calculator.h"
template <class TYPE>
Calculator<TYPE>::Calculator()
{
}
template <class TYPE>
TYPE Calculator<TYPE>::Sum(TYPE param1, TYPE param2){
cout << "Calculator::sum" << endl;
cout << param1 <<endl;
cout << param2 <<endl;
TYPE result = param1 + param2 ;
return result;
}
Main.cpp
#include <iostream>
using namespace std;
#include "Calculator.h"
int main(int argc, const char * argv[]) {
cout << "Hello, Calculator!\n";
Calculator<int> cObj;
int out = cObj.Sum(2,3);
cout << "out : " << out << endl;
Calculator<string> cObjS;
string outS = cObjS.Sum("A", "B");
cout << "outS : " << outS << endl;
cout << "Bye, Calculator!\n";
return 0;
}
Additionally, you can refer to the post, to know about how to keep the template source and header contents, and knowing about how to fix the compilation and linker issues (with reasons).
I tried to implement Properties in c++. I don't no why but if I want to compile my code there are quite a lot of errors. The main Idea was, that a template class and the tamplate constructor will give the requirement Informations.
I would be grateful if somebody could help me!
Compiling Message:
pi#raspberrypi ~/dev/property $ gcc -std=c++0x -o PropertyTest2 PropertyTest2.cpp
PropertyTest2.cpp:22:16: error: expected ‘;’ at end of member declaration
PropertyTest2.cpp:22:19: error: expected unqualified-id before ‘<’ token
PropertyTest2.cpp: In function ‘int main()’:
PropertyTest2.cpp:34:20: error: use of deleted function ‘PropertyTestClass::PropertyTestClass()’
PropertyTest2.cpp:8:7: error: ‘PropertyTestClass::PropertyTestClass()’ is implicitly deleted because the default definition would be ill-formed:
PropertyTest2.cpp:8:7: error: no matching function for call to ‘Property<int>::Property()’
PropertyTest2.cpp:8:7: note: candidates are:
Property4.cpp:21:2: note: template<int (** G)(), void (** S)(int&)> Property::Property()
Property4.cpp:6:7: note: constexpr Property<int>::Property(const Property<int>&)
Property4.cpp:6:7: note: candidate expects 1 argument, 0 provided
Property4.cpp:6:7: note: constexpr Property<int>::Property(Property<int>&&)
Property4.cpp:6:7: note: candidate expects 1 argument, 0 provided
PropertyTest2.cpp:38:20: error: no matching function for call to ‘Property<int>::Set(int)’
PropertyTest2.cpp:38:20: note: candidate is:
Property4.cpp:30:7: note: void Property<T>::Set(T&) [with T = int]
Property4.cpp:30:7: note: no known conversion for argument 1 from ‘int’ to ‘int&’
Property Class (Property.cpp)
#ifndef __PROPERTY_FH__
#define __PROPERTY_FH__
template <class T>
class Property {
private:
typedef T (*TGetter)(void);
typedef void (*TSetter)(T &);
TGetter Getter;
TSetter Setter;
public:
typedef T type;
template<TGetter *G,
TSetter *S
>
Property() {
this->Getter = G;
this->Setter = S;
}
T Get(void) {
return (this->Getter)();
}
void Set(T &value) {
(this->Setter)(value);
}
};
#endif
Testing file (PropertyTest.cpp):
#ifndef __PROPERTY_TEST_FH__
#define __PROPERTY_TEST_FH__
#include <iostream>
#include "Property.cpp"
class PropertyTestClass {
private:
// ReadWrite Property for age
int _age;
int AgeGetter(void) {
return this->_age;
}
void AgeSetter(int &value) {
this->_age = value;
}
public:
// ReadWrite Property for age
Property<int> age<&PropertyTestClass::AgeGetter, &PropertyTestClass::AgeSetter>;
};
#endif
/**
* Program Entry
**/
int main() {
std::cout << "Property Test Programm\n\n";
PropertyTestClass propTest;
std::cout << "ReadWrite Property for age\n";
propTest.age.Set(5);
std::cout << propTest.age.Get() << "\n";
return 0;
}
Ok, this time fixed all the problems in your code.
Property.cpp:
#ifndef __PROPERTY_FH__
#define __PROPERTY_FH__
#include <boost/function.hpp>
template <class T>
class Property {
private:
typedef boost::function <T()> TGetter;
typedef boost::function <void(const T&)> TSetter;
TGetter Getter;
TSetter Setter;
public:
typedef T type;
Property(TGetter G, TSetter S) {
this->Getter = G;
this->Setter = S;
}
T Get(void) {
return (this->Getter)();
}
void Set(const T &value) {
(this->Setter)(value);
}
};
#endif
PropertyTests.cpp:
#ifndef __PROPERTY_TEST_FH__
#define __PROPERTY_TEST_FH__
#include <iostream>
#include <boost/bind.hpp>
#include "Property.cpp"
class PropertyTestClass {
private:
// ReadWrite Property for age
int _age;
int AgeGetter() {
return this->_age;
}
void AgeSetter(const int &value) {
this->_age = value;
}
public:
// ReadWrite Property for age
Property<int> age;
PropertyTestClass() : age(
boost::bind(&PropertyTestClass::AgeGetter, this),
boost::bind(&PropertyTestClass::AgeSetter, this, _1))
{}
};
#endif
/**
* Program Entry
**/
int main() {
std::cout << "Property Test Programm\n\n";
PropertyTestClass propTest;
std::cout << "ReadWrite Property for age\n";
propTest.age.Set(5);
std::cout << propTest.age.Get() << "\n";
return 0;
}
Output:
$ ./a.out
Property Test Programm
ReadWrite Property for age
5
I am reading a book "Data Structures and Algorithms in C++" which was published at 2001, I think the c++ compiler should be changed a lot since that time, because I found the code in the book can not be compiled.
#include <fstream.h>
#include <string.h>
So I Google for the answer, and changed the code to
#include <fstream>
#include <cstring>
using namespace std;
But when I tried to compile the code, well, I got some error I have not ever seen:
oo#oo:~/raf$ g++ database.cpp personal.cpp student.cpp useDatabase.cpp -o useDatabase
In file included from /usr/include/c++/4.6/ios:45:0,
from /usr/include/c++/4.6/istream:40,
from /usr/include/c++/4.6/fstream:40,
from personal.h:4,
from student.h:1,
from student.cpp:1:
/usr/include/c++/4.6/bits/ios_base.h: In copy constructor ‘std::basic_ios<char>::basic_ios(const std::basic_ios<char>&)’:
/usr/include/c++/4.6/bits/ios_base.h:788:5: error: ‘std::ios_base::ios_base(const std::ios_base&)’ is private
/usr/include/c++/4.6/bits/basic_ios.h:64:11: error: within this context
In file included from /usr/include/c++/4.6/istream:41:0,
from /usr/include/c++/4.6/fstream:40,
from personal.h:4,
from student.h:1,
from student.cpp:1:
/usr/include/c++/4.6/ostream: In copy constructor ‘std::basic_ostream<char>::basic_ostream(const std::basic_ostream<char>&)’:
/usr/include/c++/4.6/ostream:57:11: note: synthesized method ‘std::basic_ios<char>::basic_ios(const std::basic_ios<char>&)’ first required here
In file included from student.cpp:1:0:
student.h: In function ‘std::ostream& operator<<(std::ostream&, Student&)’:
student.h:17:39: note: synthesized method ‘std::basic_ostream<char>::basic_ostream(const std::basic_ostream<char>&)’ first required here
student.h:15:18: error: initializing argument 1 of ‘std::ostream& Student::writeLegibly(std::ostream)’
student.cpp: At global scope:
student.cpp:24:10: error: prototype for ‘std::ostream& Student::writeLegibly(std::ostream&)’ does not match any in class ‘Student’
student.h:15:18: error: candidate is: std::ostream& Student::writeLegibly(std::ostream)
student.cpp: In member function ‘std::istream& Student::readFromConsole(std::istream&)’:
student.cpp:34:5: error: ‘cout’ was not declared in this scope
In file included from /usr/include/c++/4.6/ios:45:0,
from /usr/include/c++/4.6/ostream:40,
from /usr/include/c++/4.6/iostream:40,
from useDatabase.cpp:1:
/usr/include/c++/4.6/bits/ios_base.h: In copy constructor ‘std::basic_ios<char>::basic_ios(const std::basic_ios<char>&)’:
/usr/include/c++/4.6/bits/ios_base.h:788:5: error: ‘std::ios_base::ios_base(const std::ios_base&)’ is private
/usr/include/c++/4.6/bits/basic_ios.h:64:11: error: within this context
In file included from /usr/include/c++/4.6/iostream:40:0,
from useDatabase.cpp:1:
/usr/include/c++/4.6/ostream: In copy constructor ‘std::basic_ostream<char>::basic_ostream(const std::basic_ostream<char>&)’:
/usr/include/c++/4.6/ostream:57:11: note: synthesized method ‘std::basic_ios<char>::basic_ios(const std::basic_ios<char>&)’ first required here
In file included from useDatabase.cpp:2:0:
student.h: In function ‘std::ostream& operator<<(std::ostream&, Student&)’:
student.h:17:39: note: synthesized method ‘std::basic_ostream<char>::basic_ostream(const std::basic_ostream<char>&)’ first required here
student.h:15:18: error: initializing argument 1 of ‘std::ostream& Student::writeLegibly(std::ostream)’
oo#oo:~/raf$
I spent a lot of time to Google for the answer, but got even more error. Maybe I should register a Github account and upload my code there.
database.cpp
#include "database.h"
template<class T> Database<T>::Database() {
cout << "File name: ";
cin >> fName;
}
template<class T> void Database<T>::add(T& d){
database.open(fName, ios::in|ios::out|ios::binary);
database.seekp(0, ios::end);
d.writeToFile(database);
database.close();
}
template<class T> void Database<T>::modify(const T& d){
T tmp;
database.open(fName, ios::in|ios::out|ios::binary);
while(!database.eof()){
tmp.readFromFile(database);
if (tmp == d){
cin >> tmp;
database.seekp(-d.size(), ios::cur);
tmp.writeToFile(database);
database.close();
return;
}
}
database.close();
cout << "The record to be modified is not in the database\n";
}
template<class T> bool Database<T>::find(const T& d){
T tmp;
database.open(fName, ios::in|ios::binary);
while(!database.eof()){
tmp.readFromFile(database);
if (tmp == d){
database.close();
return true;
}
}
database.close();
return false;
}
template<class T> ostream& Database<T>::print(ostream& out){
T tmp;
database.open(fName, ios::in|ios::binary);
while(1){
tmp.readFromFile(database);
if (database.eof())
break;
out << tmp << endl;
}
database.close();
return out;
}
template<class T> void Database<T>::run() {
char option[5];
T rec;
cout << "1.Add 2.Find 3.Modify a record 4.Exit\n";
cout << "Enter an option: ";
cin.getline(option, 4);
while (cin.getline(option, 4)){
if (*option == '1'){
cin >> rec;
add(rec);
}
else if (*option == '2'){
rec.readKey();
cout << "The record is ";
if (find(rec) == false)
cout << "not ";
cout << "in the database\n";
}
else if (*option == '3'){
rec.readKey();
modify(rec);
}
else if (*option != '4'){
cout << "Wrong option\n";
}
else return;
cout << *this;
cout << "Enter an option";
}
}
database.h
#ifndef DATABASE
#define DATABASE
#include <fstream>
#include <iostream>
using namespace std;
template<class T> class Database{
public:
Database();
void run();
private:
fstream database;
char fName[20];
ostream& print(ostream&);
void add(T&);
bool find(const T&);
void modify(const T&);
friend ostream& operator<<(ostream& out, Database& db) {
return db.print(out);
}
};
#endif
personal.cpp
#include "personal.h"
#include <iostream>
Personal::Personal() : nameLen(10), cityLen(10) {
name = new char[nameLen + 1];
city = new char[cityLen + 1];
}
Personal::Personal(char *ssn, char *n, char *c, int y, long s) : nameLen(10), cityLen(10) {
name = new char[nameLen + 1];
city = new char[cityLen + 1];
strcpy(SSN, ssn);
strcpy(name, n);
strcpy(city, c);
year = y;
salary = s;
}
void Personal::writeToFile(fstream& out) const {
out.write(SSN, 9);
out.write(name, nameLen);
out.write(city, cityLen);
out.write(reinterpret_cast<const char*>(&year), sizeof(int));
out.write(reinterpret_cast<const char*>(&salary), sizeof(int));
}
void Personal::readFromFile(fstream& in) {
in.read(SSN, 9);
in.read(name, nameLen);
in.read(city, cityLen);
in.read(reinterpret_cast<char *>(&year), sizeof(int));
in.read(reinterpret_cast<char *>(&salary), sizeof(int));
}
void Personal::readKey() {
char s[80];
cout << "Enter SSN: ";
cin.getline(s, 80);
strncpy(SSN, s, 9);
}
ostream& Personal::writeLegibly(ostream& out){
SSN[9] = name[nameLen] = city[cityLen] = '\0';
out << "SSN = " << SSN << ", name = " << name
<< ", city = " << city << ", year = " << year
<< ", salary = " << salary;
return out;
}
istream& Personal::readFromConsole(istream& in){
char s[80];
cout << "SSN: ";
in.getline(s, 80);
strncpy(SSN, s, 9);
cout << "Name: ";
in.getline(s, 80);
strncpy(name, s, nameLen);
cout << "City: ";
in.getline(s, 80);
strncpy(city, s, cityLen);
cout << "Birthyear: ";
in >> year;
cout << "Salary: ";
in >> salary;
in.getline(s, 80); //get '\n'
return in;
}
personal.h
#ifndef PERSONAL
#define PERSONAL
#include <fstream>
#include <cstring>
using namespace std;
class Personal {
public:
Personal();
Personal(char*, char*, char*, int, long);
void writeToFile(fstream&) const;
void readFromFile(fstream&);
void readKey();
int size() const {
return 9 + nameLen + cityLen + sizeof(year) + sizeof(salary);
}
bool operator==(const Personal& pr) const{
return strcmp(pr.SSN, SSN) == 0;
}
protected:
const int nameLen, cityLen;
char SSN[10], *name, *city;
int year;
long salary;
ostream& writeLegibly(ostream&);
friend ostream& operator<<(ostream& out, Personal& pr){
return pr.writeLegibly(out);
}
istream& readFromConsole(istream&);
friend istream& operator>>(istream& in, Personal& pr){
return pr.readFromConsole(in);
}
};
#endif
student.cpp
#include "student.h"
Student::Student() : majorLen(10) {
Personal();
major = new char[majorLen + 1];
}
Student::Student(char *ssn, char *n, char *c, int y, long s, char *m): majorLen(11){
Personal(ssn, n, c, y, s);
major = new char[majorLen + 1];
strcpy(major, m);
}
void Student::writeToFile(fstream& out) const {
Personal::writeToFile(out);
out.write(major, majorLen);
}
void Student::readFromFile(fstream& in) {
Personal::readFromFile(in);
in.read(major, majorLen);
}
ostream& Student::writeLegibly(ostream &out){
Personal::writeLegibly(out);
major[majorLen] = '\0';
out << ", major = " << major;
return out;
}
istream& Student::readFromConsole(istream& in){
Personal::readFromConsole(in);
char s[80];
cout << "Major: ";
in.getline(s, 80);
strncpy(major, s, 9);
return in;
}
student.h
#include "personal.h"
class Student : public Personal {
public:
Student();
Student(char*, char*, char*, int, long, char*);
void writeToFile(fstream&) const;
void readFromFile(fstream&);
int size() const{
return Personal::size() + majorLen;
}
protected:
char *major;
const int majorLen;
ostream& writeLegibly(ostream);
friend ostream& operator<<(ostream& out, Student& sr){
return sr.writeLegibly(out);
}
istream& readFromConsole(istream&);
friend istream& operator>>(istream& in, Student& sr){
return sr.readFromConsole(in);
}
};
useDatabase.cpp
#include <iostream>
#include "student.h"
#include "personal.h"
#include "database.h"
int main(){
Database<Personal> db;
db.run();
}
This was a big — arguably too big — set of files to be analyzed in an SO question. You need to learn some methods of reducing the size of your problem for presentation to SO (or to Tech Support).
One of the first steps in C or C++ is to ensure that the headers you create compile cleanly. If the headers aren't clean, you won't be able to compile the code that uses the headers, so headers must be sorted out first.
To help me, I have a script that I call chkhdr:
#!/bin/sh
# Check whether headers compile
tmp=chkhdr-$$
trap 'rm -f $tmp.?; exit 1' 0 1 2 3 13 15
cat > $tmp.c <<EOF
#include HEADER /* Check self-containment */
#include HEADER /* Check idempotence */
int main(void) { return 0; }
EOF
options=
for file in "$#"
do
case "$file" in
(-*) options="$options $file";;
(*) echo "$file"
${CC:-gcc} $options -DHEADER="\"$file\"" -c $tmp.c
;;
esac
done
rm -f $tmp.?
trap 0
I use it to check that headers are both self-contained and idempotent. A self-contained header can be included without any other headers before it, and it compiles. That means it can be used anywhere its services are needed without further ado. An idempotent header can be included multiple times without causing trouble. (I mainly work in C, hence the default compiler is GCC rather than G++. But I can set CC=g++ in the environment to switch to C++ work.)
Your student.h header was not idempotent; I immediately added the standard stanzas at top and bottom:
#ifndef STUDENT_H_INCLUDED
#define STUDENT_H_INCLUDED
...original contents of student.h...
#endif /* STUDENT_H_INCLUDED */
The detailed choice of guard macro name is up to you; that's the naming scheme I use these days, but there's some merit in using something like an MD5 checksum of an draft of the header to give you a quasi-random guard macro.
The output from compiling the student.h header alone was:
In file included from chkhdr-8120.c:1:
/usr/include/c++/4.2.1/bits/ios_base.h: In copy constructor ‘std::basic_ios<char, std::char_traits<char> >::basic_ios(const std::basic_ios<char, std::char_traits<char> >&)’:
/usr/include/c++/4.2.1/bits/ios_base.h:779: error: ‘std::ios_base::ios_base(const std::ios_base&)’ is private
/usr/include/c++/4.2.1/iosfwd:55: error: within this context
/usr/include/c++/4.2.1/iosfwd: In copy constructor ‘std::basic_ostream<char, std::char_traits<char> >::basic_ostream(const std::basic_ostream<char, std::char_traits<char> >&)’:
/usr/include/c++/4.2.1/iosfwd:64: note: synthesized method ‘std::basic_ios<char, std::char_traits<char> >::basic_ios(const std::basic_ios<char, std::char_traits<char> >&)’ first required here
student.h: In function ‘std::ostream& operator<<(std::ostream&, Student&)’:
student.h:20: note: synthesized method ‘std::basic_ostream<char, std::char_traits<char> >::basic_ostream(const std::basic_ostream<char, std::char_traits<char> >&)’ first required here
student.h:20: error: initializing argument 1 of ‘std::ostream& Student::writeLegibly(std::ostream)’
The last line of the error message points firmly at the issue; the other messages are somewhat tangential, and lead up to the crux message. (Very often, especially in C, the first error is the most significant. It was surprising to me that the last line was the key one.) Changing line 20 of student.h to read:
ostream& writeLegibly(ostream&);
resolved that problem, and the student.h header compiled cleanly. The other headers were also clean. Then it was a simple matter to compile the source files. Only student.cpp had an issue:
student.cpp: In member function ‘std::istream& Student::readFromConsole(std::istream&)’:
student.cpp:34: error: ‘cout’ was not declared in this scope
It sounds like a case of 'should use std::cout instead', but adding that leads to:
student.cpp: In member function ‘std::istream& Student::readFromConsole(std::istream&)’:
student.cpp:34: error: ‘cout’ is not a member of ‘std’
That is fixed by including #include <iostream>. Then the code compiles cleanly under:
g++ -c *.cpp
I can't link; I run into undefined references to the Database code, but that's not surprising.
Summary
The details of the fixes are not incredibly important. What is important is the techniques. The key techniques here are:
Ensure headers work cleanly on their own (chkhdr).
Tackle one file at a time.
Problem minimization.
We should not have had to deal with all the code; you should have been able to isolate the problems much better. This is an important skill in any situation where you're reporting software problems to others. Eliminate the extraneous, and reduce to bare essentials.
the errors report
student.cpp:34:5: error: ‘cout’ was not declared in this scope
I think you need
#include <iostream>
In Student change
ostream& writeLegibly(ostream);
to
ostream& writeLegibly(ostream&);
and that should fix a lot. By missing the ampersand you were trying to copy the stream.
While the compiler have changed C++ and C are backwards compatible. One of the strengths of the language. Anyway I have copied out your code into a VS2010 because it was easier for me to analyse the issues with it.
put the #include < iostream > in your personal.h. It is used by personal.cpp where you have a cout.
The signature in student.h of
ostream& writeLegibly(ostream);
is wrong, it should be:
ostream& writeLegibly(ostream&);
I have moved the implementation code in database.cpp into the database.h. Plain simple cut and paste above the #endif. Due to the template nature the compiler did not like it that it was in a separate implementation cpp.
Hope that helps.