std::ostream : class is inaccesible [C++] - c++

I am getting this error in my implementation:
struct bookdatabase::Bookdatabase::Book
class "bookdatabase::BookDatabase::Book" is inaccessible
None of the following solutions solved my problem:
std::basic_ostream is inaccessible in C++
cannot access private members in friend ostream
My ostream and istream friend function can't access private class members
member of class inaccessible
Inaccessible Members ?
Here's a picture of what visual studio has issue with in the .cpp file.
Here's a picture of the declaration in the header file.
Database.h
#include <string>
#include <vector>
#ifndef BOOKDATABASE_H
#define BOOKDATABASE_H
namespace bookdatabase {
class BookDatabase {
private:
struct Book {
private:
std::string authorFirstName, authorLastName, authorFullName, bookTitle, pubDate;
public:
Book(const std::string &authFirst, const std::string &authLast, const std::string &title, const std::string &date);
std::string getAuthor() const;
std::string getBookTitle() const;
std::string getPubDate() const;
bool operator < (const Book &rhs) const;
friend std::ostream& operator << (std::ostream& out, const bookdatabase::BookDatabase::Book& book);
};
void sortBooks();
std::vector<Book>::iterator search(const std::string &title);
public:
BookDatabase();
void printBookList();
std::vector<Book> getDatabase() const;
void removeBook(const std::string &title);
void addBook(const std::string &authFirst, const std::string &authLast, const std::string &title, const std::string &date);
private:
std::vector<Book> database;
};
}
#endif // BOOKDATABASE_H
Database.cpp
std::ostream & bookdatabase::operator<<(std::ostream & out, const bookdatabase::BookDatabase::Book & book) {
out << authorFullName << ". " << bookTitle << ". " << pubDate;
return out;
}
Am I having this issue because the Book class is a nested class?

Alright, I seem to have discovered two things here which might be the problem you're having, one of which might be a bug in Visual Studio.
1. First of all, the thing which is not a bug
user0042, in his response to your post is right, operator<< being declared as friend in the struct Book results in the operator<< only being able to access private members of Book. But it cannot access Book itself, because Book is a private member of the enclosing BookDatabase class. Therefore you have to move the friend declaration to be outside Book and in BookDatabase.
Once you do that, operator<< can now access the private data member Book of BookDatabase. Note however that this does not give permission to operator<< to access the private data members of Book itself, namely authorFirstName, authorLastName, authorFullName, bookTitle, pubDate
2A. Now for the (what I believe to be) VS2017 scope operator bug
Let's say you have moved the friend declaration to BookDatabase, you still have to define the implementation in a specific way. The following two pieces of code should be equivalent ways to define the function in a Database.cpp file, but one of them doesn't work in VS2017 15.4.5.
It's ok to do
namespace bookdatabase {
ostream& operator<<(ostream& out, const bookdatabase::BookDatabase::Book& book) {
}
} // OK
But not ok to do
ostream& bookdatabase::operator<<(ostream& out, const bookdatabase::BookDatabase::Book& book) {
} // Visual Studio cannot access book
There seems to be an issue with Visual Studio's :: operator being able to obtain the friend property of a function.
So to answer your question: if you want your << operator overload to work you need to use the first method to define it in the .cpp implementation file.
2B. In fact I wrote a simple test program to show the VS2017 friend and :: bug
namespace my_namespace {
class Test {
private:
struct Nested {};
public:
friend void func(Test::Nested&);
};
void func(Test::Nested&);
}
// DOES NOT COMPILE in VS2017 15.4.5, OK in GCC 6.3 and Clang 3.8.0
// VS2017 says Nested is inaccessible
void my_namespace::func(my_namespace::Test::Nested&) {
}
But using namespace and brackets works
namespace my_namespace {
class Test {
private:
struct Nested {};
public:
friend void func(Test::Nested&);
};
void func(Test::Nested&);
}
// changed to namespace + brackets,
// COMPILES in VS2017 15.4.5, GCC 6.3 and Clang 3.8.0
namespace my_namespace {
void func(my_namespace::Test::Nested&) {
}
}
Can someone please independently verify this?
I also posted a bug report on the Microsoft Developer Community

My answer for most operator << woes is to declare a member print() method that does the hard work and call it from operator <<.
Usually I am happy for the print method to be public, and get rid of all the friend nastiness.

Related

Declaring = and [] operators for a class on the header file, "must be a nonstatic member function" error

I've made a class Block and a struct coords and while implementing the operators i came up with the errors:
'coords operator[](const Block&, const size_t&)' must be a nonstatic member function
'bool operator=(Block&, const Block&)' must be a nonstatic member function
I've declared these 2 in the header file of the class Block as follows:
class Block
{
friend Block operator+(const Block&, const coords&);
friend Block operator+(const Block&, const Block&);
friend coords operator[](const Block&, const std::size_t&);
friend void operator+=(Block&, const coords&);
friend void operator+=(Block&, const Block&);
friend bool operator=(Block&, const Block&);
//...
};
Only the operators [] and = get this error, and I'm not sure why.
I've tried to change the return value and parameter types but it keeps getting the same problem.
Are these two operators special? Or is there an error on my declarations?
I've searched for ways to solve this problem, but couldn't find a suitable answer.
Thank you for the replies.
Not all operators can be overloaded using non-member functions. [] and = are two such operators. They can be overloaded only as member functions.
See http://en.cppreference.com/w/cpp/language/operators for more details.
Those operators cannot be declared as friends. Instead you should declare like this:
coords operator[](const std::size_t&);
bool operator=(const Block&);
Your operators are also not really following conventions. Operators += and = should be returning a Block& namely *this.
The reason is exactly what the error message says: those two have to be non-static member functions. Get rid of the friend from in front of them and remove the first argument.
Further, operator+= is usually implemented as a member function, too, although it doesn't have to be. But if it is, it gives you an easy way to implement operator+ without making it a friend.
#R Sahu's link was useful, showing that [] and = can no be declared as non-member, but it didn't really explain why.
#Baum mit aguen's link cleared some other questions too.
(Thanks for the information)
So, I adjusted my code to this new information as follows:
Block.h
class Block
{
public:
//...
coords* operator[](size_t);
Block operator=(Block);
//...
};
Block.cpp
//...
coords* Block::operator[](size_t index)
{
if(index >= 0 && index < block.size())
return &block.at(index);
coords *tmp = new coords(-1, -1);
return tmp;
}
Block Block::operator=(Block b2)
{
block.empty();
block.reserve(b2.block.size());
append(b2.block);
return *this;
}
//...
This way you can call *(*b1)[0] = c1; being Block* b1 and coords c1.
The friend modifier is useful for other types of implementations, although I only realized after that the implementation of inline had to be done in the header file, not on the cpp.
Block.h
class Block
{
public:
//...
friend std::ostream& operator<<(std::ostream&, const Block&);
friend std::ostream& operator<<(std::ostream&, Block&);
//...
};
inline std::ostream& operator<<(std::ostream& out, const Block& b)
{
// do something
return out;
};
inline std::ostream& operator<<(std::ostream& out, Block& b)
{
// do something
return out;
};
In this case, you need to pass the "this" parameter has to be passed to the function also as these are non-member functions and should be implemented outside the class, in the header file.
I hope this helps, good coding everyone.

Overload math operators [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why is my log in the std namespace?
Based on Overload a C++ function according to the return value, I did the following experiment:
#include <cmath>
class myType
{
private:
double value;
myType(double value) : value(value) {}
public:
myType& operator= (const myType& other) {
if (this != &other) value = other.value;
return *this;
}
static myType test(double val) { return myType(val); }
friend std::ostream& operator<<(std::ostream& target, const myType& A);
};
std::ostream& operator<<(std::ostream& target, const myType& A){
target << A.value;
return target;
}
class asin {
private:
double value;
public:
asin(double value)
: value(std::asin( (value<-1.0) ? -1.0 : (value>1.0?1.0:value) ))
{}
operator double() { return value; }
operator myType() { return myType::test(value); }
};
int main(int argc, char *argv[])
{
myType d = asin(1.0);
std::cout << d << std::endl;
return 0;
}
which resulted in
error: ‘myType::myType(double)’ is private
on the first line in main(). A bit more experimenting showed me that this works fine and as expected when I change the classname asin to Asin (or anything else for that matter). So apparently, I'm not allowed to call my class asin, while the act of defining it (and not using it) does not give me any warning/error.
Now I know all of this is bad practice, so don't flame me for that. I ask this purely out of academic interest: why can't I call my class asin, or acos or atan or anything like that? I was under the impression that cmath hid everything in the std-namespace, so that defining this class in the global namespace would not give rise this particular problem.
Can anyone explain what's going on?
asin is a defined as global function in c++ standard library, and also defined in math library, (so you even dont have to use std::)
If you try using unamed namespace then you would get 'use of `asin' is ambiguous' error.
And named namespace solves your issue.
For some IDEs, for example Visual Studio, you do not even need to include cmath. It has these functions already defined in the global namespace. Try to exclude cmath and you will see that asin() is still defined.

C++ overloading operator<<

I'm trying to overload the << operator for a class to emulate toString() in Java. I have a NumExpr class, and has private variable number that I want to output. so here they are:
NumExpr::NumExpr( string n ) {
number = atoi( n.c_str() );
}
string NumExpr::name() {
return "num";
}
ostream & operator<<(ostream &s, const NumExpr &num) {
s << num.number;
return s;
}
I made it a friend function so it can access the private variable
class NumExpr : public Expr {
public:
NumExpr( string v );
string name();
private:
int number;
friend ostream& operator<<(ostream &s, const NumExpr &num);
};
However I'm getting this error
./ast/Expr.cpp: In function ?std::ostream& operator<<(std::ostream&, const NumExpr&)?:
./ast/Expr.cpp:50: error: no match for ?operator<NumExpr::number?
./ast/Expr.cpp:49: note: candidates are: std::ostream& operator<<(std::ostream&, const NumExpr&)
I have searched for this error, people seem to be having the same problems but mine seems to look like the solutions people are giving out. Is there something fundamentally wrong that I'm doing or is there some syntax shenanigans that I'm not aware of?
Thanks for the help!
Okay here it is, little bit of playing around I can reproduce your problem:
The problem is that You forgot to include iostream header file.
Add:
#include<iostream>
and it should just work fine :)
EDIT:
As #James Kanze correctly suggests in comments, it is sufficient to include
#include<istream>
because you don't need everything from the iostream really.
The downside of including iostream inside of istream is little increase in compilation time.
On this page:
http://www.cplusplus.com/forum/beginner/13164/
It says to have the friend function like this:
friend std::ostream& operator<< (std::ostream&, const NumExpr&); <-
so no variable decleration. just
const NumExpr
any help?

Unable match function definition to an existing definition in templated class

I'm sorry if such a question is asked before but i could not find no matter how much I searched (there were similar questions but none of them seemed to work for me).
I am writing a templated class and everything works fine except when I try to overload operator+. I try to overload operator+ two times for different parameters but compiler does not see one of the definitions and gives an eror. Here's the code:
Worker.h (one of my previos homeworks, implemented the problem here since it is easier to see ):
#ifndef _WORKER_H
#define _WORKER_H
#include <string>
#include "Project.h"
using namespace std;
template <class T>
class Worker {
public:
Worker(const string &, Project &);
void Work(const int &);
const Worker & Worker::operator+(const int &); //Problem
const Worker & Worker::operator+(const string &); //Problem
string getName() const;
int getTime() const;
private:
string myName; //The name of the worker
Project & myProject;
int myTime; //Variable to keep track of how much the worker worked.
};
#include "Worker.cpp"
#endif
and the relevant part of Worker.cpp:
template <class T>
const Worker<T> & Worker<T>::operator+(const int & add)
{
cout << add;
return *this;
}
template <class T>
const Worker<T> & Worker<T>::operator+(const string & add)
{
cout << add;
return *this;
}
+ operators are not doing anything right now, the problem is the compiler only sees first declared function (in this case the with the parameter int). There also does not seem to be problem with the functions because if I try to overload only one time, both of them work fine alone. Also I can use them (making the necessary changes) in a non-templated class.
I think it is something simple but since I'm new to templates I could not figure out what the problem was.
There are a few problems with your approach, unrelated to templates.
First your operators would only work for one ordering of operations: Worker<T> + int, and not int + Worker<T>
Second typically you would want to return a new Worker instance, not return this by reference, because A+Bshould not modify A or B.
So what you could do is define non-member operators for the different orderings:
template <typename T>
Worker<T> operator+(int i, const Worker<T>& t) { }
template <typename T>
Worker<T> operator+(const Worker<T>& t, int i) { }
and so on.
Note that for operators that should affect the state of the object, such as +=, *= and so on, the usual approach is to use member operators and return by reference, because in these cases it makes perfect sense.
2 things here, 1 of which is your issue
The return type of a member function is not affected by the fact that the class is a template, hence the declaration of operator+ returning Worker and the definition returning Worker<T> are different. In the class definition, they should be:
const Worker<T> & operator+(const int &); //Problem
const Worker<T> & operator+(const string &); //Problem
The other thing which is also changed in the above code is you don't need the scope (Worker::) in a class declaration

Class that inherits std::ostream and operator<< for QString

Hell ! I'm trying to make a class that would help me with outputting text to stdout ... Anyway, everything is working, except for one thing. Let's say that I've create object of my class called out. When I do this, everything works prefectly:
out<<"test test"<<std::endl;
And it also works when I do this:
out<<QString("another string")<<std::endl;
But, when I try to chain these two thing together, like this:
out<<"test test"<<std::endl<<QString("another string")<<std::endl;
I get that super-big error, that's eventually telling me that operator<< doesn't accept parameter of type QString. That's strange, because it works OK when I don't chain QString ... Also this works:
out<<"test test"<<std::endl<<"another string"<<std::endl;
and this:
out<<QString("another string")<<std::endl<<"test test"<<std::endl;
So I guess I have problem with my operator<< function ... Either I didn't make operator<< correctly, or I don't return correct value. Or maybe something else is wrong. Anyway, I can't figure it out, so could you help me ? Bellow is source code:
output.h: http://xx77abs.pastebin.com/b9tVV0AV
output.cpp: http://xx77abs.pastebin.com/5QwtZRXc
And of course, the super-big error :D
http://xx77abs.pastebin.com/8mAGWn47
EDIT: for all you wondering, I'm not using namespaces ...
This compiles for me (with the command line from your third link):
#include <iostream>
#include <sstream>
#include <QString>
class Output: public std::ostream
{
friend std::ostream& operator<<(std::ostream &out, const QString var);
private:
class StreamBuffer: public std::stringbuf
{
private:
std::ostream &out;
QString prefix;
public:
StreamBuffer(std::ostream& str, const QString &p);
virtual int sync();
};
StreamBuffer buffer;
public:
Output(const QString &prefix);
};
Output::Output(const QString &prefix) :
std::ostream(&buffer), buffer(std::cout, prefix)
{
}
Output::StreamBuffer::StreamBuffer(std::ostream& str, const QString &p)
:out(str)
{
prefix = p + "-> ";
}
std::ostream& operator<<(std::ostream &out, const QString var)
{
out<<qPrintable(var);
return out;
}
int Output::StreamBuffer::sync()
{
out <<qPrintable(prefix)<< str();
str("");
out.flush();
return 0;
}
int main()
{
Output out (QString (">")) ;
out<<"test test"<<std::endl;
out<<QString("another string")<<std::endl;
out<<"test test"<<std::endl<<QString("another string")<<std::endl;
}
If it compiles for you too, you should be able to morph it into your failing code to find the error.
Are you using namespaces? if you are, have you defined the operator<< for QString in a specific namespace? I can't see anything wrong with the above code (except the overload should accept a const reference rather than a copy!)
EDIT: should add, if it is in a namespace, move it out, else it will not be found.
EDIT2: add the declaration of the operator<< to the header file, after your class declaration - the compiler does not know of the existence of this overload until you do.
std::ostream& operator<<(std::ostream &out, const QString& var);
I feel compelled to note that Qt provides a function/class to do exactly this, and it's called QDebug. Since you're already bound to Qt, it should not be a problem to use it.