I've looked at several related posts but no luck with this error.
I receive this undefined reference error message below when my namespace exists across multiple files. If I compile only ConsoleTest.cpp with contents of Console.cpp dumped into it the source compiles.
I would appreciate any feedback on this issue, thanks in advance.
g++ Console.cpp ConsoleTest.cpp -o ConsoleTest.o -Wall
/tmp/cc8KfSLh.o: In function `getValueTest()':
ConsoleTest.cpp:(.text+0x132): undefined reference to `void Console::getValue<unsigned int>(unsigned int&)'
collect2: ld returned 1 exit status
Console.h
#include <iostream>
#include <sstream>
#include <string>
namespace Console
{
std::string getLine();
template <typename T>
void getValue(T &value);
}
Console.cpp
#include "Console.h"
using namespace std;
namespace Console
{
string getLine()
{
string str;
while (true)
{
cin.clear();
if (cin.eof()) {
break; // handle eof (Ctrl-D) gracefully
}
if (cin.good()) {
char next = cin.get();
if (next == '\n')
break;
str += next; // add character to string
} else {
cin.clear(); // clear error state
string badToken;
cin >> badToken;
cerr << "Bad input encountered: " << badToken << endl;
}
}
return str;
}
template <typename T>
void getValue(T &value)
{
string inputStr = Console::getLine();
istringstream strStream(inputStr);
strStream >> value;
}
}
ConsoleTest.cpp
#include "Console.h"
void getLineTest()
{
std::string str;
std::cout << "getLinetest" << std::endl;
while (str != "next")
{
str = Console::getLine();
std::cout << "<string>" << str << "</string>"<< std::endl;
}
}
void getValueTest()
{
std::cout << "getValueTest" << std::endl;
unsigned x = 0;
while (x != 12345)
{
Console::getValue(x);
std::cout << "x: " << x << std::endl;
}
}
int main()
{
getLineTest();
getValueTest();
return 0;
}
The template function needs to be defined, not only declared, in the header. The compiler needs to see the template implementation and the template argument to build the specialization you require in your main. So put the definition in the header directly:
namespace Console
{
std::string getLine();
template <typename T>
inline void getValue(T &value) {
string inputStr = Console::getLine();
istringstream strStream(inputStr);
strStream >> value;
}
}
Related
This question already has answers here:
How to initialize `std::function` with a member-function?
(3 answers)
Using generic std::function objects with member functions in one class
(6 answers)
Closed 25 days ago.
I'm trying to make a program to have a string input for choosing functions.
My code is as follows:
#include <iostream>
#include <map>
#include <functional>
#include <string>
std::map<std::string, std::function<void(bool)>>functions;
void command_greet(bool new_input);
void command_add(bool new_input);
void command_help(bool new_input);
void commands()
{
functions["hi"] = command_greet; //command
functions["add"] = command_add; //command
functions["help"] = command_help; //command
}
void command_greet(bool new_input)
{
if (new_input)
{
std::cout << "Hello!" << std::endl;
}
else
{
std::cout << "This command greets!\n";
}
}
void command_add(bool new_input)
{
if (new_input)
{
int x, y;
std::cout << "X: ";
std::cin >> x;
std::cout << "\nY: ";
std::cin >> y;
std::cout << "\n" << x + y << "\n";
std::cin.ignore();
}
else
{
std::cout << "This command adds two numbers!\n";
}
}
void command_help(bool new_input)
{
if (new_input)
{
size_t cmd_len = 0;
for (const auto& elem : functions) //calculate length of the longest command
{
if (elem.first.size() > cmd_len)
{
cmd_len = elem.first.size();
}
}
cmd_len += 4; //length plus 4 spaces
for (const auto& elem : functions)
{
std::cout << elem.first;
for (size_t i = 0; i < cmd_len - elem.first.size(); i++)
{
std::cout << ' ';
}
elem.second(false); //command description
}
}
else
{
std::cout << "This command shows commands list!\n";
}
}
int main()
{
commands();
std::string input;
while (true) //endless loop for testing
{
std::cout << "Input: ";
std::getline(std::cin, input);
if (functions.count(input) > 0)
{
functions.find(input)->second(true); //run command
std::cout << std::endl;
}
else if (input == "")
{
}
else
{
std::cerr << "'" << input << "' was not recognized.\n"
<< "Type 'help' for available commands.\n";
std::cout << std::endl;
}
}
return 0;
}
The code above works fine with no problems.
Now I want to convert it to class instead of having "bare" functions.
What I've tried:
Partial contents of cmd_console.h
#ifndef __CMD_CONSOLE__
#define __CMD_CONSOLE__
#include <iostream>
#include <string>
#include <map>
#include <functional>
class cmd_console
{
private:
std::map<std::string, std::function<void(bool)>>m_commands;
public:
cmd_console();
void cmd_logic(std::string new_input);
//...other methods here...
~cmd_console();
private:
void commands_inicialise();
//...other methods here...
void command_help(bool new_input);
//...command methods here...
void command_exit(bool new_input);
};
#endif
Partial contents of cmd_console.cpp
#include "cmd_console.h"
cmd_console::cmd_console()
{
commands_inicialise();
}
void cmd_console::commands_inicialise()
{
m_commands["HELP"] = command_help;
//Error C3867: non-standard syntax; use '&' to create a pointer to member
m_commands["EXIT"] = command_exit;
//Error C3867: non-standard syntax; use '&' to create a pointer to member
}
//...other methods here...
void cmd_console::command_help(bool new_input)
{
//code here
}
//...command methods here...
void cmd_console::command_exit(bool new_input)
{
//code here
}
cmd_console::~cmd_console()
{
}
The problem is here:
m_commands["HELP"] = command_help;
//Error C3867: non-standard syntax; use '&' to create a pointer to member
I'm unable to solve this even that it seems to be simple.
Anyone have an idea how to make it work? Thank you.
I am a beginner , so i wanted to ask , can we create a class object vector/array , that does not delete it's content when i close the program like , so like I want a customer record , but whenever if we try to restart the program we need to enter the customer details again and again ...
how to prevent that from happening
#include <iostream>
#include <vector>
using namespace std;
class customer{
public:
int balance;
string name;
int password;
};
int main(){
vector <customer> cus;
...
if(choice == 1){
cout << cus[i].balance
}
return 0;
}
As a complement to Adam's answer, it is possible to encapsulate the serialization in the container class itself. Here is an simplified example:
The header file defining a persistent_vector class that saves its content to a file:
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <initializer_list>
namespace {
// Utility functions able to store one element of a trivially copyable type
template <class T>
std::ostream& store1(std::ostream& out, const T& val) {
out.write(reinterpret_cast<const char*>(&val), sizeof(val));
return out;
}
template <class T>
std::istream& load1(std::istream& in, T& val) {
in.read(reinterpret_cast<char*>(&val), sizeof(val));
return in;
}
// Specialization for the std::string type
template <>
std::ostream& store1<std::string>(std::ostream& out, const std::string& val) {
store1<size_t>(out, val.size());
if (out) out.write(val.data(), val.size());
return out;
}
template <>
std::istream& load1<std::string>(std::istream& in, std::string& val) {
size_t len;
load1<size_t>(in, len);
if (in) {
char* data = new char[len];
in.read(data, len);
if (in) val.assign(data, len);
delete[] data;
}
return in;
}
}
template <class T>
class persistent_vector {
const std::string path;
std::vector<T> vec;
// load the vector from a file
void load() {
std::ifstream in(path);
if (in) {
for (;;) {
T elt;
load1(in, elt);
if (!in) break;
vec.push_back(elt);
}
if (!in.eof()) {
throw std::istream::failure("Read error");
}
in.close();
}
}
// store the vector to a file
void store() {
std::ofstream out(path);
size_t n = 0;
if (out) {
for (const T& elt : vec) {
store1(out, elt);
if (!out) break;
++n;
}
}
if (!out) {
std::cerr << "Write error after " << n << " elements on " << vec.size() << '\n';
}
}
public:
// a bunch of constructors, first ones load data from the file
persistent_vector(const std::string& path) : path(path) {
load();
}
persistent_vector(const std::string& path, size_t sz) :
path(path), vec(sz) {
load();
};
// last 2 constructors ignore the file because they do receive data
persistent_vector(const std::string& path, size_t sz, const T& val) :
path(path), vec(sz, val) {
};
persistent_vector(const std::string& path, std::initializer_list<T> ini) :
path(path), vec(ini) {
}
// destructor strores the data to the file before actually destroying it
~persistent_vector() {
store();
}
// direct access to the vector (const and non const versions)
std::vector<T>& data() {
return vec;
}
const std::vector<T>& data() const {
return vec;
}
};
It can, out of the box, handle any trivially copyable type and std::string. User has to provide specializations of store1 and load1 for custom types.
Here is a trivial program using it:
#include <iostream>
#include <string>
#include "persistent_vector.h"
int main() {
std::cout << "Create new vector (0) or read an existing one (1): ";
int cr;
std::cin >> cr;
if (!std::cin || (cr != 0 && cr != 1)) {
std::cout << "Incorrect input\n";
return 1;
}
if (cr == 0) {
persistent_vector<std::string> v("foo.data", 0, "");
// skip to the end of line...
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
for (;;) {
std::string line;
std::cout << "Enter a string to add to the vector (empty string to end program)\n";
std::getline(std::cin, line);
if (line.empty()) break;
v.data().push_back(line);
}
}
else {
persistent_vector<std::string> v("foo.data");
for (const std::string& i : v.data()) {
std::cout << i << '\n';
}
}
return 0;
}
When a programmer creates a vector class, he must ensure that the resources acquired for that vector are released when they are no longer needed. (See RAII)
C++ Reference : https://en.cppreference.com/w/cpp/language/raii
Wikipedia : https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization
Stack Overflow : What is meant by Resource Acquisition is Initialization (RAII)?
Microsoft : https://learn.microsoft.com/en-us/cpp/cpp/object-lifetime-and-resource-management-modern-cpp?view=msvc-170
Before the program closes, all resources must be released.
(No leaking resources, memory included)
It is not possible to create a vector class that does not delete its contents after closing a program. Secure operating systems will release program resources when the program is closed.
If you want the program not to lose customer information after closing, you need to save the information in persistent (non-volatile) storage device, such as a disk.
As CinCout, 김선달, Serge Ballesta say, you have to save the customer information to a file, and write the program so that you can read that file during the start of the program.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
struct customer {
std::string name;
int balance;
int password;
};
int main() {
std::vector <customer> customers;
std::ifstream ifs("info.txt");
{
customer customer{};
while (ifs >> customer.name >> customer.balance >> customer.password)
customers.push_back(customer);
}
for (const auto& [name, balance, password] : customers) {
std::cout <<
"\nName : " << name <<
"\nBalance : " << balance <<
"\nPassword : " << password <<
'\n';
}
std::cout << "\n\nWelcome\n\n";
std::ofstream ofs("info.txt", std::ios_base::app);
char cont{};
do {
customer customer{};
std::cout << "Name : ";
std::cin >> customer.name;
std::cout << "Balance : ";
std::cin >> customer.balance;
std::cout << "Password : ";
std::cin >> customer.password;
ofs << customer.name << ' ' << customer.balance << ' ' << customer.password << '\n';
std::cout << "Add another customer? (Y/N) : ";
std::cin >> cont;
} while (cont == 'Y');
for (const auto& [name, balance, password] : customers) {
std::cout <<
"\nName : " << name <<
"\nBalance : " << balance <<
"\nPassword : " << password <<
'\n';
}
}
CPlusPlus : https://www.cplusplus.com/doc/tutorial/files/
LearnCpp : https://www.learncpp.com/cpp-tutorial/basic-file-io/
(About File I/O)
This program is a prototype, I left some things incomplete (like check readings, user-defined I/O operators, duplicate code, formatting, reallocations of customers, ifs is not required after range-for + structured binding,...).
I suggest you read the book "Programming: Principles and Practice Using C+", I’m reading it and it helped me a lot.
(I’m also a beginner)
Edit: I also suggest you use "using namespace std;" only for small projects, examples or simple exercises.
Do not use "using namespace std;" for real projects, large projects or projects that may include other dependencies because the use of "using namespace std;" could lead to a possible naming collisions between names within std and the names of other codes and libraries.
It’s not good practice to use it all the time.
I want to search for a string in my vector. I've tried with std::find but everytime the following error appear.
54:85: error: no matching function for call to ‘std::vector<Postleitzahl>::vector(__gnu_cxx::__normal_iterator<Postleitzahl*, std::vector<Postleitzahl> >)’
54 | std::vector<Postleitzahl> it(std::find(plzVector.begin(), plzVector.end(), eingabe));
And the red pointer shows to the last ')' of "(...)it(std::find(...), eingabe));"
How can I avoid this error and what triggering it ?
Here's the code
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
class Postleitzahl
{
public:
std::string state;
std::string zipCode;
std::string city;
Postleitzahl(){}
Postleitzahl(std::string state, std::string zipCode, std::string name);
};
bool fileCheck ()
{
std::ifstream file("bundesland_plz_ort_de.txt");
if(!file)
{
std::cout << "File could not be opened!" << std::endl;
return false;
}
else
{
return true;
}
}
int main()
{
std::ifstream file("bundesland_plz_ort_de.txt");
Postleitzahl object;
std::vector<Postleitzahl> plzVector;
if(fileCheck())
{
while(file >> object.state >> object.zipCode >> object.city)
{
plzVector.push_back(object);
}
file.close();
}
std::string eingabe;
std::cout << "suche" << std::endl;
std::cin >> eingabe;
std::vector<Postleitzahl> it(std::find(plzVector.begin(), plzVector.end(), eingabe));
//if(it != plzVector.end())
// {std::cout << "Found: " << *it;
}
std::vector<Postleitzahl> it(std::find(plzVector.begin(), plzVector.end(), eingabe));
should be:
std::vector<Postleitzahl>::iterator it(std::find(plzVector.begin(), plzVector.end(), eingabe));
If you have C++11 or above you can use auto instead of std::vector<Postleitzahl>::iterator and the compiler will deduce the type automatically.
i am new to c++ from other languages, and looking at examples this code looked like it should work
#include <iostream>
using namespace std;
main()
{
string input = "";
cout << "in: ";
getline(cin, input);
input_recv(input);
}
input_recv(input)
{
if (input == "hello"){
cout << "derp" << endl;
}
}
it will not let me use the function input_recv. it gives me several errors in my IDE. one being `input_recv' undeclared (first use this function). basically what i am trying to do for this is make it respond to input using a function.
EDIT:
#include <iostream>
#include <string>
using namespace std;
void input_recv(string);
int main()
{
while (1 == 1){
string input = "";
cout << "in: ";
getline(cin, input);
input_recv(input);
cin.get();
}
}
void input_recv(string input){
if (input == "hello"){
cout << "derp" << endl;
}
}
thanks
C++ requires the function to be declared before it's used, so if you move the input_recv definition above the main function, it will work. Otherwise, you can leave the program the way it is and add a forward declaration above main like this:
void input_recv(string);
int main()
{
...
}
void input_recv(string input)
{
...
}
Edit:
There are a few other errors here as well as other comments pointed out. One, functions should have a return type and parameter types specified. Also, before using the string type, you need to
#include <string>.
Declare the function first, and use a correct function prototype, here there is not type for input, no return type ... Example below,
#include <iostream>
#include <string>
void input_recv(const std::string& input);
int main()
{
std::string input = "";
std::cout << "in: ";
std::getline(std::cin, input);
input_recv(input);
return 0;
}
void input_recv(const std::string& input)
{
if (input == "hello"){
cout << "derp" << endl;
}
}
C++ is a strongly-typed language. You must declare your variables and your functions with explicit types:
// forward declare your function
void input_recv(std::string input);
// alternatively
void input_recv_better(const std::string& input);
int main()
{
std::string input;
std::cout << "In: ";
std::getline(std::cin, input);
input_recv(input);
input_recv_better(input);
return 0;
}
void input_recv(std::string input)
{
if (input == "hello")
{
std::cout << "derp" << std::endl;
}
}
void input_recv_better(const std::string& input)
{
if (input == "hello")
{
std::cout << "derp!" << std::endl;
}
}
There's a few things definitely wrong with this snippet, I will correct them all so you can observe the difference:
#include <iostream>
using namespace std;
void input_recv(string input);
int main()
{
string input = "";
cout << "in: ";
getline(cin, input);
input_recv(input);
}
void input_recv(string input)
{
if (input == "hello"){
cout << "derp" << endl;
}
}
I have added return types to your functions, data types to your parameters, and a forward declaration of the input_recv function so that the main function knows it exists.
You will definitely want to pick up a book like C++ Primer (the latest edition revised for the C++11 standard) before learning bad practice by trying to forgo some sort of standard training.
#include <iostream>
using namespace std;
void input_recv(string input)
{
if (input == "hello"){
cout << "derp" << endl;
}
}
int main()
{
string input = "";
cout << "in: ";
getline(cin, input);
input_recv(input);
return 0;
}
I have this class:
template<typename T> class Parser
{
public:
Parser() : count(0) {}
virtual void parse(const string&);
void get_token(void);
private:
T result;
char token;
string expression;
int count;
};
now had the class not been generic, had the result been say, a double, I would have used this method to detect numbers.
while((strchr("1234567890.",token))
{
/* add token to a "temp" string */
/* etc. etc. */
}
result = atof(temp.c_str());
But since result is generic, I can't use any method like atof and atoi etc.
What do I do?
Boost has this functionality built-in:
#include <boost/lexical_cast.hpp>
void Parser<T>::get_token() {
std::string token = ...;
result = boost::lexical_cast<T>(token);
}
Add exception handling as required.
Or, perhaps you don't want to use Boost for some reason:
void Parser<T>::get_token() {
std::string token = ...;
std::stringstream ss;
ss << token;
ss >> result;
}
Check the error state of ss as required.
More expansive answers may be found on this related question, though it discusses only int specifically.
Another generic template based Numeric To String converter. It takes ints and doubles.
#include <sstream>
#include <iostream>
#include <string>
using namespace std;
template <class T>
inline std::string Numeric_To_String (const T& t)
{
std::stringstream ss;
ss << t;
return ss.str();
}
int main(int argc, char *argv[])
{
int i = 9;
double d = 1.2345;
string s;
cout <<"Generic Numeric_To_String( anyDatatype ) \n\n";
s = Numeric_To_String( i );
cout <<"int i to string : "<< s <<" "<< endl;
s = Numeric_To_String( d );
cout <<"double d to string : "<< s <<" "<< endl;
cout <<" \n";
return 0;
}
If you only have a hand full of types you want to parse, you can use template specialization:
template<>
void Parser<int>::parse(const string&)
{
result = atoi(string.c_str());
}
template<>
void Parser<float>::parse(const string&)
{
result = atof(string.c_str());
}
...
But this only works if you implement every convertion you need, of course.
With C++17 you can use the templated std::from_chars.
https://en.cppreference.com/w/cpp/utility/from_chars
#include <charconv>
#include <iostream>
template <typename Number>
auto stringTo(std::string_view str)
{
Number number;
std::from_chars(str.data(), str.data() + str.size(), number);
return number;
}
int main()
{
const auto str = std::string("42");
std::cout << stringTo<long>(str) << '\n';
std::cout << stringTo<double>(str) << '\n';
}
Check the return value of std::from_chars to detect errors.
const auto result = std::from_chars(...);
if (result.ec == std::errc::invalid_argument || result.ec == std::errc::result_out_of_range)
{
std::cout << "string to number error" << '\n';
}
More info and examples: https://www.bfilipek.com/2018/12/fromchars.html
GCC and clang don't yet support the floating point version of std::from_chars (August 2019).