C++ using ldap_bind from ldap.h - c++

I'm trying to use ldap_bind, but get an this error.
error: âldap_bindâ was not declared in this scope
code:
#include <lber.h>
#include <ldap.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
LDAP *ld;
char *ldap_host = "ldap://localhost";
int ldap_port = 389;
int auth_method = LDAP_AUTH_SIMPLE;
int desired_version = LDAP_VERSION3;
char *root_dn = "ou=people,dc=localhost,dc=local";
char *root_ps = "password";
int result;
result = ldap_initialize(&ld, ldap_host);
cout << "result: " << result << endl;
result = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &desired_version);
cout << "result: " << result << endl;
result = ldap_bind_s(ld, root_dn, root_ps, auth_method);
cout << "result: " << result << endl;
}
I'm compiling with this command
g++ ldap.cpp -llber -lldap -o prog
TIA

I've no experience with OpenLDAP, but from the header it seems you need:
extern "C" {
# define LDAP_DEPRECATED
# include <ldap.h>
# include <lber.h>
}

It leads to some compiling errors in current version, since in the ldap.h use #if LDAP_DEPRECATED instead of #ifdef, give the MACRO a value:
#define LDAP_DEPRECATED 1
And it is good to go.

Dont use ldap_bind. Its deprecated. Rather use ldap_sasl_bind.
ldap.h has deprecated a lot of functions for mostly security reasons
Check out the following command which lists all the deprecated functions
grep deprecate < /usr/include/ldap.h

On *nix systems, or any system that let's you specify compilation flags, you can add the following to your list of flags:
-DLDAP_DEPRECATED
This allows you to use the deprecated deprecated features without having to add defines to the top of all of your source/header files.

Related

Recursively including a header file over a list of values

Suppose I have an header that is meant to be included several times generating code from a template parameterised over a macro DATA. I use it in this way:
#define DATA this
#include <header.hpp>
#undef DATA
#define DATA that
#include <header.hpp>
#undef DATA
#define DATA the_other
#include <header.hpp>
#undef DATA
Is there a way to automate this repeated inclusion given a list of the values of DATA? Something like:
#define DATAS (this, that, the_other)
#include <header.hpp>
#undef DATAS
I tried with some __VA_OPT__ magic, and inside of header.hpp I can isolate the first element of the list and the tail of the list, but the problem is that I cannot redefine DATAS in terms of itself for the next inclusion.
Is this possible at all?
Yes, it is possible.
You can use Boost Preprocessor (which is independent of all other Boost Packages and only has to be downloaded, no library needs to be built or installed) to get the needed ready-to-use macros. You can also try to understand Boost Preprocessor and recreate the needed features.
The example is taken from Ari's answer. It could be expanded to provide several data elements to each iteration, e.g. for initializing the ints and floats with specific values.
// header.hpp - sample header, which uses DATA to create variables
// uses Boost preprocessor only for simple concatenation
// you can use your custom header here
#include <boost/preprocessor/cat.hpp>
int BOOST_PP_CAT(int_, DATA) = 1;
float BOOST_PP_CAT(float_, DATA) = 2.2f;
// main.cpp - wants to define lots of variables
// provides header name, list of symbol suffixes
// repeated.hpp will include header.hpp 3 times with DATA set to this, that and the_other
// (Space after REP_PARAMS is important)
#define REP_PARAMS ("header.hpp")(this, that, the_other)
#include "repeated.hpp"
#undef REP_PARAMS
#include <iostream>
using namespace std;
int main()
{
cout << "int_this: " << int_this << endl;
cout << "int_that: " << int_that << endl;
cout << "int_the_other: " << int_the_other << endl;
cout << "----------------------------------------------------------"
<< endl;
cout << "float_this: " << float_this << endl;
cout << "float_that: " << float_that << endl;
cout << "float_the_other: " << float_the_other << endl;
return 0;
}
// repeated.hpp - helper header
// all the magic
// it mostly extracts the REP_PARAMS sequence
// TODO error-checking, e.g. that REP_PARAMS exists and is a sequence of length two, that second element of REP_PARAMS is a tuple
#if !BOOST_PP_IS_ITERATING
// iteration has not started yet, include used boost headers
// initialize iteration with 3 parameters from 0 to < size of tuple,
// include itself (repeated.hpp)
#include <boost/preprocessor/iteration/iterate.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <boost/preprocessor/tuple/size.hpp>
#include <boost/preprocessor/seq/seq.hpp>
#define BOOST_PP_ITERATION_PARAMS_1 (3, (0, BOOST_PP_TUPLE_SIZE(BOOST_PP_SEQ_TAIL(REP_PARAMS)), "repeated.hpp"))
#include BOOST_PP_ITERATE()
#else
// set DATA to i-th element in tuple, include specified header (header.hpp)
#define DATA BOOST_PP_TUPLE_ELEM(BOOST_PP_ITERATION(), BOOST_PP_SEQ_TAIL(REP_PARAMS))
#include BOOST_PP_SEQ_HEAD(REP_PARAMS)
#undef DATA
#endif
The maximum list size is 256. By default it is limited to 64, but can be increased with the BOOST_PP_LIMIT_TUPLE macro.
I have to admit I wouldn't even consider using any preprocessing tricks for that. This is a classical scripting problem.
Instead you could write a small script that creates that header for you and inserts that at the beginning of the file. You could then add that as a step in your build system to run it. This technique gives you a LOT of power going forward:
You can add the same header to many scripts rather easily
You can see all the custom headers in a clean json format
You could easily get the script to add multiple #define <key> <value>-s before the include
You could change formatting easily and quickly
Here is an example script that does that:
import json
def prepend_headers(fout, headers):
for header in headers:
include = header['include']
define = header['define']
for k, v in define.items():
fout.write(f'#define {k} {v}\n')
fout.write(f'#include {include}\n')
for k, _ in define.items():
fout.write(f'#undef {k}\n')
fout.write('\n')
def main(configfile):
with open(configfile) as fin:
config = json.load(fin)
input_file = config['input']
with open(input_file) as fin:
input_content = fin.read()
output_file = config['output']
with open(output_file, 'w') as fout:
headers = config['headers']
prepend_headers(fout, headers)
fout.write(input_content)
if __name__ == '__main__':
import sys
configfile = sys.argv[1]
sys.exit(main(configfile))
If you use the following configuration:
{
"input": "class.cpp.template",
"output": "class.cpp",
"headers": [
{
"include": "<header.hpp>",
"define": {
"DATA": "this",
"OBJ": "him"
}
},
{
"include": "<header.hpp>",
"define": {
"DATA": "that"
}
},
{
"include": "<header.hpp>",
"define": {
"DATA": "the_other"
}
}
]
}
And the following template file:
#include <iostream>
class Obj {
};
int main() {
Obj o;
std::cout << "Hi!" << std::endl;
return 0;
}
The result you get is this:
#define DATA this
#define OBJ him
#include <header.hpp>
#undef DATA
#undef OBJ
#define DATA that
#include <header.hpp>
#undef DATA
#define DATA the_other
#include <header.hpp>
#undef DATA
#include <iostream>
class Obj {
};
int main() {
Obj o;
std::cout << "Hi!" << std::endl;
return 0;
}
Using a template class might be annoying, so you might decide to add some hints in the output file so you could "replace" them with every build you run.
This is not doable using preprocessor only. However, it is probably worth mentioning that there is something called X-Macro that could have been used for something close to what you are asking if you weren't using preprocessor macros for each case.
The reason is that it cannot be used here is that you cannot use #define or #include in the definition of a macro.
For example, this is doable for defining this, that and the_other as variables from a file called data.def that has them as a list:
// data.def
ELEMENT(this)
ELEMENT(that)
ELEMENT(the_other)
Then in main.cc:
//main.cc
#define ELEMENT(d) int int_##d = 1;
#include "data.def"
#undef ELEMENT
#define ELEMENT(d) int float_##d = 2.2;
#include "data.def"
#undef ELEMENT
int main() {
std::cout << "int_this: " << int_this << std::endl;
std::cout << "int_that: " << int_that << std::endl;
std::cout << "int_the_other: " << int_the_other << std::endl;
std::cout << "----------------------------------------------------------"
<< std::endl;
std::cout << "float_this: " << float_this << std::endl;
std::cout << "float_that: " << float_that << std::endl;
std::cout << "float_the_other: " << float_the_other << std::endl;
}
Output:
int_this: 1
int_that: 1
int_the_other: 1
---------------------------------------------------------------
float_this: 2
float_that: 2
float_the_other: 2
But something like this is not going to work because you would be defining a macro in another macro:
#define ELEMENT(d) #define DATA d; \
#include "data.def" \
#undef DATA
#undef ELEMENT

How to create directory c++ (using _mkdir)

Today I did a lot of research online about how to create a directory on C++
and found a lot of way to do that, some easier than others.
I tried the _mkdir function using _mkdir("C:/Users/..."); to create a folder. Note that the argument of function will be converted into a const char*.
So far, so good, but when I want to change the path, it does not work (see the code below). I have a default string path "E:/test/new", and I want to create 10 sub-folders: new1, new2, newN, ..., new10.
To do that, I concatenate the string with a number (the counter of the for-loop), converted into char using static_cast, then I transform the string using c_str(), and assign it to a const char* variable.
The compiler has no problem compiling it, but it doesn't work. It prints 10 times "Impossible create folder n". What's wrong?
I probably made a mistake when transforming the string using c_str() to a get a const char*?.
Also, is there a way to create a folder using something else? I looked at CreateDirectory(); (API) but it uses keyword like DWORD HANDLE, etc., that are a little bit difficult to understand for a no-advanced level (I don't know what these mean).
#include <iostream>
#include <Windows.h>
#include<direct.h>
using namespace std;
int main()
{
int stat;
string path_s = "E:/test/new";
for (int i = 1; i <= 10; i++)
{
const char* path_c = (path_s + static_cast<char>(i + '0')).c_str();
stat = _mkdir(path_c);
if (!stat)
cout << "Folder created " << i << endl;
else
cout << "Impossible create folder " << i << endl;
Sleep(10);
}
return 0;
}
If your compiler supports c++17, you can use filesystem library to do what you want.
#include <filesystem>
#include <string>
#include <iostream>
namespace fs = std::filesystem;
int main(){
const std::string path = "E:/test/new";
for(int i = 1; i <= 10; ++i){
try{
if(fs::create_directory(path + std::to_string(i)))
std::cout << "Created a directory\n";
else
std::cerr << "Failed to create a directory\n";\
}catch(const std::exception& e){
std::cerr << e.what() << '\n';
}
}
return 0;
}
The problem is that (path_s + static_cast<char>(i + '0')) creates a temporary object. One whose life-time ends (and is destructed) just after c_str() has been called.
That leaves you with a pointer to a string that no longer exist, and using it in almost any way will lead to undefined behavior.
Instead save the std::string object, and call c_str() just when needed:
std::string path = path_s + std::to_string(i);
_mkdir(path.c_str());
Note that under Linux, you can use the mkdir command as follows:
#include <sys/stat.h>
...
const int dir_err = mkdir("foo", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
if (-1 == dir_err){
printf("Error creating directory!n");
exit(1);
}
More information on it can be gleaned from reading man 2 mkdir.

‘multiline’ is not a member of ‘std::__cxx11::regex’

I am trying to compile the following C++ code using the command:
g++ -std=c++17 -o rgx rgx.cpp
#include <iostream>
#include <regex>
#include <string>
using namespace std;
int main() {
regex rgx("^([A-Z]*)$", regex::ECMAScript | regex::multiline | regex::icase);
smatch rmtch;
string str = "AbcefgH\r\nTest";
if (regex_match(str, rmtch, rgx)) {
for (size_t i = 0; i < rmtch.size(); i++) {
ssub_match smtch = rmtch[i];
string s_m = smtch.str();
cout << " submatch " << i << ": " << s_m << endl;
}
}
return 0;
};
However get the following compile time error
rgx.cpp: In function ‘int main()’:
rgx.cpp:7:53: error: ‘multiline’ is not a member of ‘std::__cxx11::regex’ {aka ‘std::__cxx11::basic_regex<char>’}
7 | regex rgx("^([A-Z]*)$", regex::ECMAScript | regex::multiline | regex::icase);
g++ --version
g++ (Ubuntu 9.1.0-8ubuntu1) 9.1.0
Why is g++ using __cxx11::regex when I've specified -std=c++17?
cppreference.com/w/cpp/regex/basic_regex defines regex::multiline as being part of the C++17 standard
Libstdc++ doesn't appear to implement regex::multiline.
Note that the fact that it's using std::__cxx11::regex doesn't mean that you're stuck in the past. __cxx11 is not strictly reserved to C++11 features. The purpose of inline namespaces (such as __cxx11) is that if eventually a class/struct needs to change in ways that are not backwards compatible, new programs will grab its definition from a new inline namespace while the old definition remains for programs that were built before.

Using header files correctly

I'm trying to expand my C++ game hacking skills as when I was starting (2 years ago) I made a bad decision: continue in game hacking with vb.net instead of learning c++ (as I had some vb.net knowledge and 0 knowledge with other languages)
So, now as the very first steps I have to create my toolkit, where I will be using my own templates:
Nathalib.h (my template with all common functions for game hacking).
#pragma once
#include <iostream>
#include <Windows.h>
#include <string>
#include <TlHelp32.h>
#include <stdio.h>
using namespace std;
DWORD ProcessID;
int FindProcessByName(string name)
{
HWND hwnd = FindWindowA(0, name);
GetWindowThreadProcessId(hwnd, &ProcessID);
if (hwnd)
{
return ProcessID;
}
else
{
return 0;
}
}
Hack.cpp (obviously the cheat, will be different for every game).
#pragma once
#include "pch.h"
#include <iostream>
#include <Windows.h>
#include <string>
#include <Nathalib.h>
using namespace std;
int main()
{
While(True)
{
cout << FindProcessByName("Calculator") << endl;
getchar();
cout << "-----------------------------------" << endl << endl;
}
return 0;
}
Target.cpp (as we're not bad boys, I must provide my own target).
#include "pch.h"
#include <iostream>
#include <Windows.h>
#include <string>
using namespace std;
#define CHAR_ARRAY_SIZE 128
int main()
{
int varInt = 123456;
string varString = "DefaultString";
char arrChar[CHAR_ARRAY_SIZE] = "Long char array right there ->";
int * ptr2int;
ptr2int = &varInt;
int ** ptr2ptr;
ptr2ptr = &ptr2int;
int *** ptr2ptr2;
ptr2ptr2 = &ptr2ptr;
while(True) {
cout << "Process ID: " << GetCurrentProcessId() << endl;
cout << "varInt (0x" << &varInt << ") = " << varInt << endl;
cout << "varString (0x" << &varString << ") = " << varString << endl;
cout << "varChar (0x" << &arrChar << ") = " << arrChar << endl;
cout << "ptr2int (0x" << hex << &ptr2int << ") = " << ptr2int << endl;
cout << "ptr2ptr (0x" << hex << &ptr2ptr << ") = " << ptr2ptr << endl;
cout << "ptr2ptr2 (0x" << hex << &ptr2ptr2 << ") = " << ptr2ptr2 << endl;
cout << "Press ENTER to print again." << endl;
getchar();
cout << "-----------------------------------" << endl << endl;
}
return 0;
}
I don't know why the header file is not being recognized.
This is the correct way to include header files? Should I create a namespace/class/object for calling it?
It's the correct way creating a header file? Or I should create another kind of project/resource for this purpose?
How should I call my library methods? Like LibraryName.MethodName?
I just come from other languages and some ideas/features are not available in the other languages (that's why I'm interested in this one)
If there's something I forgot to add, please tell me and I will update
Thanks
There are multiple errors - please check your textbook.
You include your own headers with #include "". System headers are included with #include<>
The header file generally contains function declarations. Function bodies go into the corresponding .cpp file.
You call your library functions by their name. If they're in a namespace, that might mean the format is namespacename::functionname(arguments).
There are two ways to include headers, using "" or <>
with <> the file will be searched in the system search path (which is not the $PATH variabel, but the list of paths provided with `-I' together with standard headers already known by compiler) and included if found
with "" the file will be search in the current folder and in the system search path
Assuming your header is in th esame folder of hack.cpp, you should use
#include "Nathalib.h"
First off, your header lacks include guards, #pragma once only works with msvc++.
Your header file is probably not in PATH, so you need to specify it's path relative to your project. If your header file is in the same root as your cpp file, all you need to do is change the include statement for that header file to #include "Nathalib.h" otherwise you'll have to specify the relative path.
To add to other aswers- why you should put declaration of function in .h file, while its definition to .cpp file: Writing function definition in header files in C++
I suggest to find some c++ tutorials for example: http://www.tutorialspoint.com/cplusplus/cpp_functions.htm
You should learn tutorials first, making some exercises on simply code. Personally I prefer check then most simply code for new programming construct. Then more complicated.
After such learning you may use for reference also : http://www.cplusplus.com and https://en.cppreference.com/w/

C++ Primer chapter 9 does not compile: `useConvs.cc:50:19: error: call of overloaded ‘stod(std::string&)’ is ambiguous`

I bought the C++ Primer 5th edition and downloaded the accompanying zip file with sources. The zip file is developed for GCC version 4.7.0
I'm on Linux, Ubuntu 13.10 and GCC version 4.8.1
As a sanity check for my system setup and the contents of the download, I tried to compile the examples by typing make in the folder where I unpacked the zip file. All examples compiled except for chapter 9. I checked the CompilerNotes.pdf that came in the zip archive, but it doesn't mention this particular error message.
My question is
How can I fix chapter 9 source code in the zip file in such a way that the code compiles as intended and the code still reasonably lines up with the book?
The compiler error is:
g++ -std=c++0x -I.. -I..\7 -c useConvs.cc -o useConvs.o
useConvs.cc: In function ‘int main()’:
useConvs.cc:50:19: error: call of overloaded ‘stod(std::string&)’ is ambiguous
double d = stod(s); // converts the string s to floating-point
^
useConvs.cc:50:19: note: candidates are:
In file included from useConvs.cc:33:0:
../Version_test.h:86:8: note: double stod(const string&, std::size_t*)
double stod(const std::string &s, std::size_t * = 0)
^
In file included from /usr/include/c++/4.8/string:52:0,
from /usr/include/c++/4.8/bits/locale_classes.h:40,
from /usr/include/c++/4.8/bits/ios_base.h:41,
from /usr/include/c++/4.8/ios:42,
from /usr/include/c++/4.8/ostream:38,
from /usr/include/c++/4.8/iostream:39,
from ../Version_test.h:70,
from useConvs.cc:33:
/usr/include/c++/4.8/bits/basic_string.h:2853:3: note: double std::stod(const string&, std::size_t*)
And the same error is repeated for line 55. Line 50 reads:
double d = stod(s); // converts the string s to floating-point
The source code:
/*
* This file contains code from "C++ Primer, Fifth Edition", by Stanley B.
* Lippman, Josee Lajoie, and Barbara E. Moo, and is covered under the
* copyright and warranty notices given in that book:
*
* "Copyright (c) 2013 by Objectwrite, Inc., Josee Lajoie, and Barbara E. Moo."
*
*
* "The authors and publisher have taken care in the preparation of this book,
* but make no expressed or implied warranty of any kind and assume no
* responsibility for errors or omissions. No liability is assumed for
* incidental or consequential damages in connection with or arising out of the
* use of the information or programs contained herein."
*
* Permission is granted for this code to be used for educational purposes in
* association with the book, given proper citation if and when posted or
* reproduced.Any commercial use of this code requires the explicit written
* permission of the publisher, Addison-Wesley Professional, a division of
* Pearson Education, Inc. Send your request for permission, stating clearly
* what code you would like to use, and in what specific way, to the following
* address:
*
* Pearson Education, Inc.
* Rights and Permissions Department
* One Lake Street
* Upper Saddle River, NJ 07458
* Fax: (201) 236-3290
*/
// Version_test.h contains definitions for to_string and stod
// if the compiler does not yet define these functions,
// this code will use the definitions we provide
#include "Version_test.h"
#include <string>
using std::string;
#ifdef STRING_NUMERIC_CONVS
using std::to_string; using std::stod;
#endif
#include <iostream>
using std::cout; using std::endl;
int main()
{
int i = 42;
// converts the int i to its character representation
string s = to_string(i);
double d = stod(s); // converts the string s to floating-point
cout << "i = " << i << " s = " << s << " d is: " << d << endl;
// convert the first substring in s that starts with a digit, d = 3.14
string s2 = "pi = 3.14";
d = stod(s2.substr(s2.find_first_of("+-.0123456789")));
cout << "d = " << d << " s = " << s << " s2 is: " << s2 << endl;
return 0;
}
// Version_test.h contains definitions for to_string and stod
// if the compiler does not yet define these functions,
// this code will use the definitions we provide
#include "Version_test.h"
The code in question assumes that the compiler does not have definitions for those functions, and provides it's own definitions in that header. But it seems that in your particular case the compiler does provide that functionality and it conflicts with those provided in the zip.
Unqualified lookup finds ::strod, and ADL finds ::std::strod, with the exact same signatures and the compiler cannot determine a better candidate for overload resolution. My guess is that the simple solution is to remove that header, or if your implementation does not provide a to_string then comment out the strod
Try disambiguating the calls by prefixing std:: wherever to_string and stod are present:
int main()
{
int i = 42;
// converts the int i to its character representation
string s = std::to_string(i);
double d = std::stod(s); // converts the string s to floating-point
cout << "i = " << i << " s = " << s << " d is: " << d << endl;
// convert the first substring in s that starts with a digit, d = 3.14
string s2 = "pi = 3.14";
d = std::stod(s2.substr(s2.find_first_of("+-.0123456789")));
cout << "d = " << d << " s = " << s << " s2 is: " << s2 << endl;
return 0;
}
Let me explain you line by line what gets wrong in here (I have copied "Version_test.h" inside the main.cpp - that is what #include does):
#ifndef VERSION_TEST_H
#define VERSION_TEST_H
#if __cplusplus == 201103L
// base version, future releases of this file will
// #define these variables as features as they are implemented
/* Code in this delivery use the following variables to control compilation
Variable tests C++ 11 Feature
HEX_MANIPS hexfloat and defaultfloat manipulators
REFMEMS reference qualified member functions
REGEX regular expressions library
STRING_NUMERIC_CONVS conversions to and from string to numeric
*/
#endif // ends compiler version check
#ifndef STRING_NUMERIC_CONVS
// if the library doesn't define to_string
// or the numeric conversion functions
// as a workaround we define to_string and stod in this file
// Readers can ignore the implemnetations of to_string and stod
// but can use these functions in their code.
#include <iostream>
#include <cstdlib>
#include <cstddef>
#include <string>
// we use sprintf from stdio to implement to_string
#include <cstdio>
inline
string to_string(int i)
{
char buf[100];
std::sprintf(buf, "%d", i);
return buf;
}
inline
double stod(const std::string &s, std::size_t * = 0)
{
char **buf = 0;
return std::strtod(s.c_str(), buf);
}
#endif // STRING_NUMERIC_CONVS
#include <iostream>
#ifndef HEX_MANIPS
inline
std::ostream &defaultfloat(std::ostream &os)
{
os.unsetf(std::ios_base::floatfield);
return os;
}
#endif // HEX_MANIPS
#endif // ends header guard
#include <string>
using std::string;
#ifdef STRING_NUMERIC_CONVS
using std::to_string; using std::stod;
#endif
#include <iostream>
using std::cout; using std::endl;
int main()
{
int i = 42;
// converts the int i to its character representation
string s = to_string(i);
double d = stod(s); // converts the string s to floating-point
cout << "i = " << i << " s = " << s << " d is: " << d << endl;
// convert the first substring in s that starts with a digit, d = 3.14
string s2 = "pi = 3.14";
d = std::stod(s2.substr(s2.find_first_of("+-.0123456789")));
cout << "d = " << d << " s = " << s << " s2 is: " << s2 << endl;
return 0;
}
Let's keep a register of what functions we have declared when STRING_NUMERIC_CONVS was not defined.
Take a closer look here:
inline
std::string to_string(int i)
{
char buf[100];
std::sprintf(buf, "%d", i);
return buf;
}
inline
double stod(const std::string &s, std::size_t * = 0)
{
char **buf = 0;
return std::strtod(s.c_str(), buf);
}
You create new functions (don't care about inline now - it will work even without these).
We registered:
string to_string(int i)
double stod(const std::string &s, std::size_t * = 0)
Now let's look here.
#ifdef STRING_NUMERIC_CONVS
using std::to_string; using std::stod;
#endif
We didn't declare STRING_NUMERIC_CONVS (that's the case we're looking at, check few lines up) so there is no code here.
Author of the book thought that this will prevent std::stod usage (we are not using std::stod;), but he or she didn't think about something very important: the line using std::stod; is actually written - somewhere in the Standard Library (it can be <iostream> or <cstdlib>, whatever).
The same situation goes for several different functions like atoi(); or atof();
That's what we actually have declared now:
string to_string(int i)
double stod(const std::string &s, std::size_t * = 0)
double std::stod(const std::string &s, std::size_t * = 0)
using std::stod - somewhere in the standard library.
That makes a problem: writing stod(); will actually refer to two functions (check with the list above).
As long as stod() is global (I mean - used without any std::) we can do nothing to prevent it from declaration.
In order to keep the book's purposes we should consider what exactly the STRING_NUMERIC_CONVS macro is. It asks if there are some already defined functions for string conversions. As long as you use any standard library (like iostream) you will always have some functions already defined.
So the thing is, that when we use any standard library, we declare the macro STRING_NUMERIC_CONVS, and when we don't use any standard library (and we always do) we don't declare the macro.
We use such libraries (and hence, even between the #ifndef and #endif we include such libs) so we declare the macro. Corrected, working code:
#define STRING_NUMERIC_CONVS
#include "Version_test.h"
#include <string>
using std::string;
#ifdef STRING_NUMERIC_CONVS
using std::to_string; using std::stod;
#endif
#include <iostream>
using std::cout; using std::endl;
int main()
{
int i = 42;
// converts the int i to its character representation
string s = to_string(i);
double d = stod(s); // converts the string s to floating-point
cout << "i = " << i << " s = " << s << " d is: " << d << endl;
// convert the first substring in s that starts with a digit, d = 3.14
string s2 = "pi = 3.14";
d = std::stod(s2.substr(s2.find_first_of("+-.0123456789")));
cout << "d = " << d << " s = " << s << " s2 is: " << s2 << endl;
return 0;
}
David Rodríguez - dribeas put me on the right track, but the comments are not fit for a code sniplet that covers couple lines.
I solved the compiler errors by adding the following two lines in ../Version_test.h:
#define REFMEMS
#define STRING_NUMERIC_CONVS
I added them after this paragraph on lines 48-60:
#if __cplusplus == 201103L
// base version, future releases of this file will
// #define these variables as features as they are implemented
/* Code in this delivery use the following variables to control compilation
Variable tests C++ 11 Feature
HEX_MANIPS hexfloat and defaultfloat manipulators
REFMEMS reference qualified member functions
REGEX regular expressions library
STRING_NUMERIC_CONVS conversions to and from string to numeric
*/
#endif // ends compiler version check