Effective c++ item 3 example - c++

My question is about a specific item (3) of the book "Effective C++". The book gives this example that I tried to reproduce as close as possible into vs 2010 c++ (including iostream and string):
class TextBlock {
public:
const char& operator[](std::size_t pos) const
{
return text[pos];
}
char& operator[](std::size_t pos)
{
return text[pos];
}
private:
std::string text;
};
void print(const TextBlock& ctb)
{
std::cout << ctb[0]; // OK
//ctb[0] = ‘A’; // Not OK – compiler error
}
int _tmain(int argc, _TCHAR* argv[])
{
TextBlock tb(“Hello”);
std::cout << tb[0];
tb[0] = ‘x’; // OK because return has &, not const
const TextBlock ctb("World");
std::cout << ctb[0];
return 0;
}
And I get these compiling errors:
1>c:\users\lalancelot\documents\visual studio 2010\projects\item3\item3.cpp(31): error C2065: '“Hello”' : undeclared identifier
1>c:\users\lalancelot\documents\visual studio 2010\projects\item3\item3.cpp(33): error C2065: '‘x’' : undeclared identifier
1>c:\users\lalancelot\documents\visual studio 2010\projects\item3\item3.cpp(34): error C2664: 'TextBlock::TextBlock(const TextBlock &)' : cannot convert parameter 1 from 'const char [6]' to 'const TextBlock &'
1> Reason: cannot convert from 'const char [6]' to 'const TextBlock'
1> No constructor could take the source type, or constructor overload resolution was ambiguous
Let me first say that I am discouraged to already be stuck at this early stage of the book. I have somehow found informations here:
difference between static_cast<const A>(*this) and static_cast<const A&>(*this),
but not a working answer like the one in the book. I would like to make the book example work so I can understand how it works. I've been stuck on this one for many days now and I must admit that I need help. I would like to know if I am missing a base concept here or if I am way over my head. Thanks.

What kind of quotes are you using? I ask because when I look at your
code, I see distinct opening and closing quotes, and when I copy/paste
it into my editor, it indicates that they are Unicode opening and
closing quotes. All punctuation in a C++ program should be pure
ASCII: 0x22 for the double quotes (both opening and closing), and 0x27
for the single quotes. This is also what the corresponding characters
on the keyboard should give you when entering text in a program
editor. (Do not use a word processor for entering code.)

The class TextBlock needs a constructor to be constructable from a text:
explicit TextBlock( const std::string& s ) : text( s )
{
}
Maybe there is a website to the book where you can look up corrections to the book.

Related

Why std::string reference cannot take char*?

I have simple code.
template<typename T>
class NamedObject{
public:
NamedObject(std::string& name, const T& value):nameValue(name), objectValue(value)
{
}
private:
std::string& nameValue;
const T objectValue;
};
int main(int argc, char* argv[])
{
NamedObject<int> no1("Smallest Prime Number",2);//error
NamedObject<int> no2(std::string("Smalledst Prime Number"),2);//works
return 0;
}
When I make first parameter as non refrence, both no1 and no2 object gets created. But when I keep reference Visual Studio compiler gives following error,
Error 1 error C2664: 'NamedObject::NamedObject(std::string &,const
T &)' : cannot convert parameter 1 from 'const char [22]' to
'std::string &' c:\users\pkothari\documents\visual studio
2008\projects\stackoflw\stackoflw\stackoflw.cpp 36
If char * can be casted to std::string, why not to std::string& ? Is there any way to make it work?
NamedObject<int> no2(std::string("Smalledst Prime Number"),2);//works
That should not work in a standard compliant compiler. It is supported in MS Visual Studio C++ even though it is not standard C++.
Neither of the following calls should work when the expected argument is std::string&.
NamedObject<int> no1("Smallest Prime Number",2);
NamedObject<int> no2(std::string("Smalledst Prime Number"),2);
Both of them should work when the argument type is std::string or std::string const&.

Assigning to ostream_iterators using *

On page 107 of Stroustrup's The C++ Programming language (4th ed) is an example of writing to ostream_iterators through assignment to them. A word for word copy of a subset of the example is below, but I can not compile it on VS2015 without an error and I do not understand the error message
std::ostream_iterator<string> oo { cout };
*oo2 = "Hello, "; // compile error, see below
++oo2;
I also tried
*oo2 = string("Hello"); // same error
the beginning of the very long error message follows
1>c:\program files (x86)\microsoft visual studio 14.0\vc\include\iterator(317): error C2679: binary '<<': no operator found which takes a right-hand operand of type 'const std::string' (or there is no acceptable conversion)
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\ostream(495): note: could be 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(std::basic_streambuf<char,std::char_traits<char>> *)'
<...more...>
A different version using char *'s works fine:
// works
std::ostream_iterator<const char *> oo5{ std::cout }; //const or no const, either works
*oo5 = "hello, ";
++oo5;
*oo5 = " world\n";
What is wrong with the string version? Is this a error in the book or on my part somehow? Thanks
edit
I'll also note that:
std::ostream_iterator<char> oo{ std::cout };
string s{ "hello, stream_iterator<char>, copy string" };
std::copy(s.begin(), s.end(), oo);
works
Your code has a typo. Does this work any better?
#include <iostream>
#include <ostream>
#include <string>
int main()
{
std::ostream_iterator<std::string> oo2{ std::cout };
*oo2 = "Hello, ";
++oo2;
return 0;
}
I get this output:
Hello,

Cannot convert from 'initializer-list' to 'std::initializer_list<Keyword> &'

I'm trying to use an initialization-list to pass a list of keywords to a tokenizer to register. But it does not work in Visual Studio 2013. It works in gcc at ideone.com. Is there any way to use this or a similar syntax in VS?
struct Keyword
{
const char* name;
int id;
};
void AddKeywords(int group, std::initializer_list<Keyword>& lis) {}
// usage
AddKeywords(ITEM_TYPE, {
{ "weapon", IT_WEAPON },
{ "armor", IT_ARMOR }
});
Full error:
item.cpp(810): error C2664: 'void AddKeywords(int,std::initializer_list<Keyword> &)' : cannot convert argument 2 from 'initializer-list' to 'std::initializer_list<Keyword> &'
You are trying to bind a temporary to a non-const reference;
std::initializer_list<Keyword>& lis
Try either;
std::initializer_list<Keyword> const& lis
Or
std::initializer_list<Keyword> lis
When building with GCC, enable -Wall -pedantic it should give you an error then as well.

Pseudo-code given in class that I'm trying to comprehend with the associated lab assignment in c++

So I've tried to figure out what exactly the professor was writing on the board and how it answers the lab assignment we are to do.
This is the lab assignment:
Create a Hash Table and Hash map that holds all of the WORDS in the (given below) Declaration of Independence.
Handle collisions using the chain method. (Note we will not be modifying this table nor doing deletions!)
Programmatically answer the following questions:
What is the size of your hash table?
What is the longest collision (ie. Chain)
What is the most frequently used word and how did you determine it?
Create a (second) Hash Table that holds all of the LETTERS in the Declaration of Independence.
What is the size of your hash table
What letter has the longest collision?
And this is the pseudo-code with some modifications that I did to fix some errors:
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <list>
using namespace std;
class Translate
{
string word;
public:
int trans(string word);
w = word.charAT(0); //gives a letter
return #num;
};
class HashTable
{
int size();
int collision();
int length();
char fword();
public:
Translate t;
list<string> hashTable[29];
bool insert(string word)
{
hashTable[t.trans(word)].push_back(word);
return true;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
HashTable h;
open file f("hash.txt");
//h.insert(word)
while (!f.eof())
{
h.insert(f.word());
}
cout << h.size;
cout << h.collision.length;
cout << h.fword;
return 0;
}
The errors that I have are:
Error 15 error C1903: unable to recover from previous error(s); stopping compilation
Error 5 error C2014: preprocessor command must start as first nonwhite space
Error 4 error C2059: syntax error : 'return'
Error 13 error C2065: 'f' : undeclared identifier
Error 10 error C2065: 'file' : undeclared identifier
Error 8 error C2065: 'open' : undeclared identifier
Error 6 error C2143: syntax error : missing ';' before '}'
Error 1 error C2143: syntax error : missing ';' before '='
Error 11 error C2146: syntax error : missing ';' before identifier 'f'
Error 9 error C2146: syntax error : missing ';' before identifier 'file'
Error 14 error C2228: left of '.eof' must have class/struct/union
Error 3 error C2238: unexpected token(s) preceding ';'
Error 7 error C2238: unexpected token(s) preceding ';'
Error 12 error C3861: 'f': identifier not found
Error 2 error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
Error 19 IntelliSense: '#' not expected here
Error 17 IntelliSense: class "std::basic_string, std::allocator>" has no member "charAT"
Error 21 IntelliSense: expected a ';'
Error 18 IntelliSense: expected a declaration
Error 22 IntelliSense: identifier "f" is undefined
Error 20 IntelliSense: identifier "open" is undefined
Error 16 IntelliSense: this declaration has no storage class or type specifier
I've never used .c_str and I'm still pretty new to C++ so my knowledge is limited. I can tell that there are places that need an identifier but I think there is a better way to create a "open file". My previous knowledge is C#, HTML, and some Python in which C++ is giving me some difficulty in learning and understanding. Any help and/or insight would be greatly appreciated!
Code is too mangled to understand. However, I'm trying my best to help with the little knowledge of mine on C++ and hash.
Proposed Code Modification
Program entry point : instead of int _tmain(int, _TCHAR*), use int main().This should guarantee you the ability to test things out should you migrate to non-windows compiler.
Source : Unicode _tmain vs main
I would like to help with the remainder, however, the code posted is way too unintelligible. Would be kind if the algorithm is posted for reference.
There are a few things you should change:
Assuming trans() is supposed to be a function definition, not a declaration, and the lines following it are supposed to be the body:
Unless you specifically want to copy the passed string, you should use const string& instead of string.
It should have braces.
w is a char.
std::string defines operator[], so it can be indexed like an array.
I'm not sure what #num is (I assume it's from Python, but I'm not familiar with that), so I'm not sure how you intend to calculate the return value.
[I will thus assume that you want to return w, but as an int instead of a char. If this is the case, it would be simpler to just return word[0];.]
There are a few issues with HashTable's members.
Member functions size(), collision(), length(), and fword() are private. This doesn't appear to be intentional.
Member variables t and hashTable are public, when you likely wanted them to be private. Again, this doesn't appear to be intentional.
The functions aren't actually defined anywhere, unless you didn't show their definitions. This will cause a linking error when you call them.
While this doesn't need to be changed, there's no reason for HashTable::insert() to actually return a value, if it's hard-coded to always return true. Also, as mentioned in 1.1 above, the parameter should probably be const string&.
_tmain() and _TCHAR are a Microsoft extensions, which is available on Visual Studio and some (but not all) compilers aiming for compatibility with it (such as C++Builder). If you want your code to be platform-independent, you likely want main(). [Note that this doesn't need to be changed. If you're only compiling with Visual Studio, you can leave it as is. If you want platform independence, you can easily define _tmain and _TCHAR yourself.]
Opening a file:
Neither open nor file are keywords in C++, nor are they types (although FILE is a C type, it doesn't appear to be what you want). You appear to want std::ifstream.
You shouldn't use !f.eof() as a condition in a while loop, because eofbit won't be set until after reading fails.
fstream has no member function word(). However, the extraction operator, operator>>() will read a single word at a time, if given a parameter that can accept one.
HashTable::size(), HashTable::collision(), HashTable::length(), and HashTable::fword() are functions. To call them, you use operator(). If you just use a function's name directly, you don't call it, but instead refer to it (this can be used to create a function pointer or function reference).
int has no member function length(). Therefore, you cannot call h.collision().length(). In C++, if you chain function calls like that, each function in the chain is treated as if it were a member function of the directly preceding type, not the leftmost type; this means that for every function after the first, the return type of the preceding function is used. (In this case, h.collision() returns an int, so .length() attempts to call member function int::length(). int isn't a class type, and thus doesn't have any member functions.)
So, considering these, your code can be modified as follows:
// Assuming your stdafx.h contains "#include <string>" and "#include <tchar.h>".
// If it doesn't, either put them there, or #include them here.
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <list>
// #4: Defining _tmain and _TCHAR
#ifndef _tmain
#define _tmain main
typedef char _TCHAR;
#endif
using namespace std;
class Translate
{
string word;
public:
// #1: Fixing trans().
int trans(const string& word)
{
char w = word[0]; // First letter of word.
return w; // Will be promoted to int.
}
};
class HashTable
{
// #2: Making member functions public, and member variables private.
Translate t;
list<string> hashTable[29];
public:
int size();
int collision();
int length();
char fword();
// #3: Making word a const reference. Changing return type to void.
void insert(const string& word)
{
hashTable[t.trans(word)].push_back(word);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
HashTable h;
// #5.1: Opening the file.
ifstream f("hash.txt");
//h.insert(word)
// #5.2 & 5.3: Reading a word.
std::string word;
while (f >> word)
{
h.insert(word);
}
// #6: Calling functions.
cout << h.size();
cout << h.collision(); // #7: Assuming you wanted to output both h.collision() and
cout << h.length(); // h.length(), I put them on separate lines.
// If you actually DID want h.collision().length(), then
// h.collision() should return a type (or reference to a type)
// with member function length(), or be an instance
// (or reference to an instance) of a class with member function
// length() (instead of being a function).
cout << h.fword();
return 0;
}
You still need to provide bodies for HashTable's member functions, apart from insert(), as well as make any other modifications you desire. You might also want to remove member word from Translate, if it doesn't actually need to store a string.

C++ type cast operator code that won't compile in visual studio 2012, but worked fine in visual studio 2005

I'm trying to update a old project that has been building with visual studio 2005 to uses visual studio 2012, and I'm getting an error that I cant solve.
The code that works fine under VS2005:
#include <iostream>
#include <string>
#include <sstream>
using std::cout;
using std::wcout;
using std::endl;
using std::wstring;
using std::string;
class Value
{
public:
Value(const wstring& value)
{
v = value;
}
Value(Value& other)
{
this->v = other.v;
}
template<typename T>
operator T() const
{
T reply;
std::wistringstream is;
is.str(v);
is >> reply;
return reply;
}
operator wstring() const
{
return v;
}
private:
wstring v;
};
int main()
{
Value v(L"Hello World");
wstring str = v;
wcout << str << endl;
Value int_val(L"1");
int i = int_val;
cout << i + 1 << endl;
return 0;
}
When I'm compiling this under VS2012 I get an error on the line "wstring str = v;", the error is:
error C2440: 'initializing' : cannot convert from 'Value' to 'std::basic_string<_Elem,_Traits,_Alloc>'
1> with
1> [
1> _Elem=wchar_t,
1> _Traits=std::char_traits<wchar_t>,
1> _Alloc=std::allocator<wchar_t>
1> ]
1> No constructor could take the source type, or constructor overload resolution was ambiguous
I can kinda fix it by changing the operator signature from 'operator wstring() const' to 'operator const wstring&() const'. But why does the original code not work, even though it works in VS2005.
I'm not getting an error on the line "int i = int_val;".
This also compiles and runs fine with GCC (g++) in cygwin (version 4.5.3).
Update
To really simulate my real problem there was some information left out in the sample code above. In between the Value class and the usage is a few other classes. One that look like this:
class Config
{
public:
virtual Value getValue(const string& key) const = 0;
Value operator()(const string& key)
{
return getValue(key);
}
};
And the usage
const wstring value2 = config("key");
That will give the error above when compiling but also IntelliSense will give other hints on whats wrong and it says: "More than one user-defined conversion from "Value" to "const std::wstring" applies:" and it points at both the regular constructor and the move constructor of basic_string. So it seem to have something to do with rvalues to do and I have been reading up on that, and understand the basics. But there is probably a lot I am missing.
I find that I can fix this problem by changing the usage to:
const wstring&& value = config("key");
Then it seem like the VS2012 compiler understand which constructor it should use then.
Questions:
* Are there a way to not use && in this example?
* What is really happening here?
I put up the sample code on GitHub:
https://github.com/Discordia/ImplicitTypeConversion
In simple (hopefully not simplified) terms, with C++11, you'll have to start thinking of references in terms of lvalue and rvalue. Basically, C++11 gives you the ability to handle operations on references differently depending on whether or not you are dealing with a "temporary" object. This gives you ability to do things like move data internal to your object rather than copy in different situations. The down side to this is the effect you are seeing, where old code is not specific enough about which you are dealing with. There's more to it than that, it's not really something that can be fully explained in a short SO answer, but previous answers gave some good places to start. I would rework your code to provide both rvalue and lvalue operators (which it sounds like you're already on your way to doing).