implicit operator bool() is not responding to my call - c++

I am testing a template:
template<typename Key>
struct _Tarray<Key, char>{
map<const Key, string> data;
//stuff
operator bool(){cout << " just testing"; return false;} //trying to call this, but its not answering
};
So, I am driving it like this:
_Tarray<int, char> out;
cout << out;
Here is my overloaded operator<<:
template<typename T, typename U>
ostream& operator<< (ostream& os, const _Tarray<T, U>& var){
//now i expect operator bool() to be called here
if(var){os << " Yes !";} //and bool is not being called. my compiler (g++) is angry
else{cout << " No !";}
return os;
}
Which gives me
./template.h: In instantiation of 'std::ostream& operator<<(std::ostream&, const _Tarray<T, U>&) [with T = int; U = char; std::ostream = std::basic_ostream<char>]':
./template.h:128:41: required from 'void var_dump(const T&) [with T = _Tarray<int, char>]'
functions.cpp:12:21: required from here
./template.h:122:5: error: passing 'const _Tarray<int, char>' as 'this' argument discards qualifiers [-fpermissive]
if(var){os << "heheheheh";}
^
./template.h:73:5: note: in call to '_Tarray<Key, char>::operator bool() [with Key = int]'
Why is it giving me a compiler error and what can I do to fix it?

var is a const _Tarray<T, U>&. The important information here is that it is const, which means, that no function can be called from var if they modify the properties of var.
The compiler doesn't know that your operator bool doesn't modify anything, so it fails. You have to explicitly state that your operator bool won't modify _Tarray, by specifying the function as const:
//Note the 'const', operator bool own't change anything, so the call from a const
//instance is legal
operator bool() const
{
std::cout << "Just testing\n";
return false;
}

In your operator<< var is const. Since it is const you can only call const qualified member functions. Since your operator bool is not marked as const you cannot use it. To fix it change operator bool to
operator bool() const {cout << " just testing"; return false;}

Related

How to use enable_if to conditionally define a << operator

I'm trying to define a << operator for a set of classes; the set is open, but all of the members have a common tagging base class, and all have the member function std::string String() const. Basically, what I've got is:
class Tag {};
class Obj : public Tag
{
public:
std::string String() const { return "specialized"; }
};
template <typename T>
typename std::enable_if<std::is_base_of<Tag, T>::type, std::ostream>::value& operator<<( std::ostream& dest, T const& source)
{
dest << source.String();
return dest;
}
int
main()
{
std::cout << typeid(std::enable_if<std::is_base_of<Tag, Obj>::value, std::ostream>::type).name() << std::endl;
std::string s( "generic" );
Obj e;
std::cout << e << std::endl;
std::cout << s << std::endl;
return 0;
}
This doesn't work: with g++ (version 4.8.3, invoked with -std=c++11), I get the error message:
enableIf.cc: In function 'int main()':
enableIf.cc:55:18: error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'
std::cout << e << std::endl;
^
In file included from /usr/lib/gcc/x86_64-pc-cygwin/4.8.3/include/c++/iostream:39:0,
from enableIf.cc:8:
/usr/lib/gcc/x86_64-pc-cygwin/4.8.3/include/c++/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 = Obj]'
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
^
I can't figure it out, because there aren't any rvalue-references in sight; the compiler seems to have struck on the generic overload for std::ostream&& in the standard library.
With MSC (VS 2013), the error message is a lot more verbose, but it starts with:
enableIf.cc(55) : error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'Obj' (or there is no acceptable conversion)
and then goes on to list a lot of possible functions, all in the standard library.
(In my actual code, line 55 corresponds to the line std::cout << e << std::endl;.)
In both cases, the compiler seems to be rejecting my overloaded function. If I comment out the << lines, however, the code compiles, and the value output by the first line in main seems correct (at least with MSC—the output of g++ is So, what ever that's supposed to mean).
Given that two compilers agree, I assume that there is an error in my code, but I can't figure out what. How do you do this? (FWIW: I'd be equally happy, or even happier, with a solution which generates the overload for all types having a member function std::string Type::String() const.)
I'm pretty sure you meant this:
template <typename T> // here here
typename std::enable_if<std::is_base_of<Tag, T>::type, std::ostream>::value&
operator<<( std::ostream& dest, T const& source)
to be this:
template <typename T>
typename std::enable_if<std::is_base_of<Tag, T>::value, std::ostream>::type&
operator<<( std::ostream& dest, T const& source)
after changing as such, you compile successfully.

Trying to print vector of objects with overloading?

I'm working on a hash table program involving linear probing. I'm trying to print out the vector of Symbol class objects but I'm running into two errors every time I try to do it. I've posted these errors below:
LinearProbing.h: In instantiation of 'void HashTable<HashedObj>::print() [with HashedObj = Symbol]':
Driver.cpp:79:21: required from here
LinearProbing.h:82:4: error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'
In file included from /opt/local/include/gcc47/c++/iostream:40:0,
from Driver.cpp:1:
/opt/local/include/gcc47/c++/ostream:600: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 = HashTable<Symbol>::HashEntry]'
Here is where I'm trying to print the vector in the HashTable class...
class HashTable
{
///...
void print()
{
typename vector<HashEntry>::iterator vIter = array.begin;
while(vIter != array.end())
{
cout<< *vIter << "\n";
++vIter;
}
}
private:
vector<HashEntry> array;
};
And my overloading in the Symbol class...
friend ostream & operator <<(ostream & outstream, Symbol & symbol) //overloaded to print out the the HashTable
{
int num = symbol.type;
string name = symbol.data;
outstream << name << " : " << num << "\n";
return outstream;
}
Not sure what you're doing there but you have defined a vector of HashEntry and calling cout on HashEntry but your operator<< overload operates on Symbol instead.
The operator<< for class Symbol should look something like this
class Symbol {
private:
friend ostream& operator<<(ostream &os, const Symbol &s);
int type;
string data;
};
ostream& operator<<(ostream &os, const Symbol &s)
{
os << s.data << " : " << s.type;
return os;
}

Why does outputting a class with a conversion operator not work for std::string?

This works, printing 1:
#include <iostream>
struct Int {
int i;
operator int() const noexcept {return i;}
};
int main() {
Int i;
i.i = 1;
std::cout << i;
}
However, this fails to compile on GCC 4.8.1:
#include <iostream>
#include <string>
struct String {
std::string s;
operator std::string() const {return s;}
};
int main() {
String s;
s.s = "hi";
std::cout << s;
}
Here are the relevant parts of the error:
error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream}’ and ‘String’)
std::cout << s;
snip
template std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::basic_string<_CharT, _Traits, _Alloc>&)
operator<<(basic_ostream<_CharT, _Traits>& __os,
/usr/include/c++/4.8/bits/basic_string.h:2753:5: note: template argument deduction/substitution failed:
main.cpp:25:18: note: ‘String’ is not derived from ‘const std::basic_string<_CharT, _Traits, _Alloc>’
std::cout << s;
I only use std::cout and std::string, which have the same template arguments. I'm really not sure why this wouldn't be able to pick up the implicit conversion like it did for Int. Why does it work with int, but not std::string?
That operator is a free template function. User defined conversions do not get checked when matching against a template function arguments, it instead uses type pattern matching (substitution).
In theory a SFINAE overload using std::is_convertable<> would be able to do what you want, but that technique was not used when operator<< that outputs a std::string to a basic_ostream<char> was defined.
A manual overload to output your class to basic_ostream<...> will fix your problem.
I would do this:
struct String {
std::string s;
operator std::string() const {return s;}
friend std::ostream& operator<<( std::ostream& os, String const& self) {
return os<<self.s;
}
};
which has the added benefit of not creating a wasted copy.
The << operator seems to have a pool of overloads with types other than std::string.
as I have seen by using the clang++ compiler.
The compiler does the implicit conversion from String to std::string but it does not match any of the defined << operators.
If you define the << operator for std::string it will work
#include <iostream>
#include <string>
std::ostream& operator<<(std::ostream& s, const std::string& str)
{
s << str.c_str();
return s;
}
struct String {
std::string s;
operator std::string() const {return s;}
};
int main() {
String s;
s.s = "hi";
std::cout << s;
}
You can find more details on the same issue here: http://forums.codeguru.com/showthread.php?432227-RESOLVED-Implicit-conversion-to-std-string
As seen in one post;
The problem is the operator<< here is a template and no template instantiations can be made for the type TestClass since the user defined conversions are probably not being considered in argument deduction for templates for implicit instantiations (atleast I could not find in section 14.7.1 (Implicit instantiation). This results in an empty overload set for the call "std::cout << obj << '\n';" and hence the error. It does not matter if an instantiation already happened or not. Template candidates are chosen into overload set on exact matches (except for array to pointer decay and const qualification - http://groups.google.co.in/group/com...29910b6?hl=en&).
When you provide an explicit overload operator<< with type std::string, it is non-template and adds up in the overload set and hence invoking the implicit conversion while doing overload resolution/a callable match.

implicit conversion operator

I want to print all the arguments of function using variadic templates feature of C++11. And I did the following:
struct concatenate
{
template< typename ...ARGS >
explicit
concatenate(ARGS const & ...args)
{
cat(args...);
}
/*explicit*/
operator std::string const () const
{
return oss.str();
}
private :
std::ostringstream oss;
void cat() const
{ ; }
template< typename T, typename ...ARGS >
void cat(T const & head, ARGS const & ...tail)
{
if (oss.tellp() > 0) {
oss << ' ';
}
oss << head;
cat(tail...);
}
};
Then I try to test it:
std::cout << '\'' << concatenate(1, 2, 3, 4, std::string("ololo"), "alala", 'o', 1.2, 1.2L, 1.2f) << '\'' << std::endl;
but then given the code does not compile with error:
error: cannot bind 'std::basic_ostream<char>' lvalue to 'std::basic_ostream<char>&&'
c:\mingw\lib\gcc\mingw32\4.7.0\include\c++\ostream:600: 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 = concatenate]'
What is the nature of the error? After all, the compiler has no choice but to use a conversion operator. It isn't?
operator << for class template std::basic_string is defined as (free) function template. In contrast with non-template functions, template argument deduction doesn't involve possible argument conversions. Templated operator << for basic_string needs exactly a string as it right argument and implicit conversion (from concatenate to string) doesn't work.
Because you're not using the explicit conversion operator and you have not overloaded operator<< for your class it tries to call:
template <class charT, class traits, class T>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>&& os, const T& x);
Using the explicit conversion
std::string(concatenate(1, 2, 3, 4, std::string("ololo"), "alala", 'o', 1.2, 1.2L, 1.2f))
does the right thing.

Conversion operators

This code is not compilable.
I can't find why in standard. Can someone explain?
#include <iostream>
#include <string>
template<typename T>
class S
{
public:
explicit S(const std::string& s_):s(s_)
{
}
std::ostream& print(std::ostream& os) const
{
os << s << std::endl;
return os;
}
private:
std::string s;
};
template<typename T>
std::ostream& operator << (std::ostream& os, const S<T>& obj)
{
return obj.print(os);
}
/*template<>
std::ostream& operator << <std::string> (std::ostream& os, const S<std::string>& obj)
{
return obj.print(os);
}*/
class Test
{
public:
explicit Test(const std::string& s_):s(s_)
{
}
//operator std::string() const { return s; }
operator S<std::string>() const { return S<std::string>(s); }
private:
std::string s;
};
int main()
{
Test t("Hello");
std::cout << t << std::endl;
}
Compiler output:
source.cpp: In function 'int main()':
source.cpp:47:17: error: no match for 'operator<<' in 'std::cout << t'
source.cpp:47:17: note: candidates are:
In file included from include/c++/4.7.1/iostream:40:0,
from source.cpp:1:
include/c++/4.7.1/ostream:106:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ostream_type& (*)(std::basic_ostream<_CharT, _Traits>::__ostream_type&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
include/c++/4.7.1/ostream:106:7: note: no known conversion for argument 1 from 'Test' to 'std::basic_ostream<char>::__ostream_type& (*)(std::basic_ostream<char>::__ostream_type&) {aka std::basic_ostream<char>& (*)(std::basic_ostream<char>&)}'
....
Thats because no conversions, except for array-to-pointer, function-to-pointer, lvalue-to-rvalue and top-level const/volatile removal (cf. c++11 or c++03, 14.8.2.1), are considered when matching a template function. Specifically, your user-defined conversion operator Test -> S<string> is not considered when deducing T for your operator<< overload, and that fails.
To make this universal overload work, you must do all the work at the receiving side:
template <class T>
typename enable_if<is_S<T>::value, ostream&>::type operator <<(ostream&, const T&);
That overload would take any T, if it weren't for the enable_if (it would be unfortunate, since we don't want it to interfere with other operator<< overloads). is_S would be a traits type that would tell you that T is in fact S<...>.
Plus, there's no way the compiler can guess (or at least it doesn't try) that you intended to convert Test to a S<string> and not S<void> or whatever (this conversion could be enabled by eg. a converting constructor in S). So you have to specify that
Test is (convertible to) an S too
the template parameter of S, when converting a Test, is string
template <class T>
struct is_S {
static const bool value = false;
};
template <class T>
struct is_S<S<T>> {
static const bool value = true;
typedef T T_type;
};
template <>
struct is_S<Test> {
static const bool value = true;
typedef string T_type;
};
You will have to convert the T to the correct S manually in the operator<< overload (eg. S<typename is_S<T>::T_type> s = t, or, if you want to avoid unnecessary copying, const S<typename is_S<T>::T_type> &s = t).
The first paragraph of #jpalecek's answer explains what the issue is. If you need a workaround, you could add a declaration like:
inline std::ostream& operator<< (std::ostream& os, const S<std::string>& s)
{ return operator<< <> (os, s); }
Since that overload is not a template, implicit conversions to S<std::string> will be considered.
But I can't see any way to do this for all types S<T>...