calling std::minus can't work after overloading - operator - c++

Am getting compilation errors for the following snippet of my C++ code.
struct Power{
int power;
int age;
int operator-(const Power& p1)
{
return this->power - p1.power;
}
};
int main() {
Power p1;
p1.power = 1;
p1.age = 25;
Power p2;
p2.power = 2;
p2.age = 26;
std::cout<<std::minus<Power>()(p1, p2)<<std::endl;
}
build with c++11. cannot be built.
error messages are:
error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘Power’)
std::cout<<std::minus<Power>()(p1, p2)<<std::endl;
^
In file included from /usr/include/c++/5/iostream:39:0,
from rvaluereference.cpp:1:
/usr/include/c++/5/ostream:628:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = Power] <near match>
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
^
/usr/include/c++/5/ostream:628:5: note: conversion of argument 1 would be ill-formed:
rvaluereference.cpp:60:39: error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
.....

std::minus has a single template parameter that defines the type of both inputs and the output; it doesn't handle type switching AFAICT. Your operator- takes Power, and returns int, but std::minus<Power> must take and return Power. The complaint is because std::minus<Power> returns Power, and ostream doesn't have an overload for operator<< that accepts Power.
As noted in the comments, if you can use C++14, std::minus<void> accepts mismatched arguments and deduces the return type, so if you can use C++14, that's another option.

While std::minus only can do T operator-(const T &lhs, const T &rhs), your operators do not have the same limitations. Declare the operator outside of the class:
int operator-(const Power &lhs, const Power &rhs) {
return lhs.power - rhs.power;
}
and now you can do std::cout << p1 - p2 << std::endl;

Related

Using a template function in an anonymous namespace

I am trying to use Strong Types and to add stream operator for them.
In my source file I put all of these helpers in an anonymous namespace. One of these helpers is using a template stream operator (utils::to_hex(T)) defined in another header.
namespace { // Anonymous namespace
// Example custom strong type
using custom_type = utils::StrongType<std::uint32_t, struct Custom>;
// Stream operator for custom type
std::ostream &operator<<(std::ostream &_os, const custom_type &_value)
{
return (_os << utils::to_hex(static_cast<std::uint32_t>(_value)));
}
}
int main(void)
{
custom_type c = 0xDEADBEEF;
std::cout << c << std::endl;
}
The whole code: http://cpp.sh/2ln7q
I cannot compile this code. I am stuck with:
test.cc: In function ‘std::ostream& {anonymous}::operator<<(std::ostream&, const custom_type&)’:
test.cc:72:14: error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘utils::ToHex<unsigned int>’)
return (_os << utils::to_hex(static_cast<std::uint32_t>(_value)));
Using the cpp.sh compiler I got:
In function 'std::ostream& {anonymous}::operator<<(std::ostream&, const custom_type&)':
73:65: error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'
In file included from /usr/include/c++/4.9/istream:39:0,
from /usr/include/c++/4.9/sstream:38,
from /usr/include/c++/4.9/iomanip:45,
from 3:
/usr/include/c++/4.9/ostream:602:5: note: 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 = utils::ToHex<unsigned int>]'
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
When I remove the anonymous namespace of if I use the static keyword everything is fine.

GCC problem with static_cast<std::u16string>

Summary
I have a class to which I've added a typecast operator to convert to std::u16string. The signature of this operator looks as follows:
operator const std::u16string() const;
In my .cpp file, I try converting an object of my class's type to std::u16string as follows:
std::u16string sUTF16Password = static_cast<std::u16string>(Password_);
On Visual Studio 2017, this works just fine. However, GCC 6.3 on my Raspberry Pi gives the following error at compile time:
error : call of overloaded 'basic_string(MyClass&)' is ambiguous
What is the right way to write this typecast? Searching on Google brings a lot of hits for character encoding conversions, but that's not my problem here. I don't understand why the basic_string constructor is being called here despite using static_cast.
Full example
Here's a minimal example. Compiling it with g++ main.cpp fails on my Raspberry Pi.
#include <iostream>
#include <string>
class MyClass
{
private:
std::u16string Str;
public:
MyClass() { Str = u"abcd"; }
operator const char16_t*() const { return Str.c_str(); }
operator std::u16string() const { return Str; }
};
int main()
{
MyClass Tester;
std::u16string TestStr = static_cast<std::u16string>(Tester);
for (size_t idx = 0; idx < TestStr.size(); idx++)
std::cout << idx << ": " << TestStr[idx] << std::endl;
return 0;
}
The output of gcc --version is gcc (Raspbian 6.3.0-18+rpi1+deb9u1) 6.3.0 20170516.
The full output from g++ main.cpp is:
main.cpp: In function ‘int main()’:
main.cpp:17:61: error: call of overloaded ‘basic_string(MyClass&)’ is ambiguous
std::u16string TestStr = static_cast<std::u16string>(Tester);
^
In file included from /usr/include/c++/6/string:52:0,
from /usr/include/c++/6/bits/locale_classes.h:40,
from /usr/include/c++/6/bits/ios_base.h:41,
from /usr/include/c++/6/ios:42,
from /usr/include/c++/6/ostream:38,
from /usr/include/c++/6/iostream:39,
from main.cpp:1:
/usr/include/c++/6/bits/basic_string.h:476:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::__cxx11::basic_string<_
CharT, _Traits, _Alloc>&&) [with _CharT = char16_t; _Traits = std::char_traits<char16_t>; _Alloc = std::allocator<char16_t>]
basic_string(basic_string&& __str) noexcept
^~~~~~~~~~~~
/usr/include/c++/6/bits/basic_string.h:454:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&
) [with _CharT = char16_t; _Traits = std::char_traits<char16_t>; _Alloc = std::allocator<char16_t>]
basic_string(const _CharT* __s, const _Alloc& __a = _Alloc())
^~~~~~~~~~~~
/usr/include/c++/6/bits/basic_string.h:397:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_st
ring<_CharT, _Traits, _Alloc>&) [with _CharT = char16_t; _Traits = std::char_traits<char16_t>; _Alloc = std::allocator<char16_t>]
basic_string(const basic_string& __str)
^~~~~~~~~~~~
If I remove the typecast to const char16_t* this example compiles just fine. I still don't understand why having both typecasts is a problem.
If you compile as C++14 (or earlier), you'll get this ambiguous call, because std::u16string(char16_t*) participates in the overload resolution (via MyClass::operator const char16_t*()) as well as MyClass::operator std::u16string() that would appear to be a better match.
This can be overcome in several ways:
Compile as C++17 (or later) with GCC 7 or later (sadly, this doesn't help with GCC 6).
Remove operator const char16_t*().
Add explicit to operator const char16_t*() (or to both conversion operators).

C++ Trying to display data of different types using a template output function

I have made a function that is supposed to output data types which include ints, chars, strings and a class called item. This is the function:
template < typename T >
void Output(const T* first, const T* last, char outforchar= '\0')
{
if (outforchar== '\0')
{
std::for_each(first, last, [](T i){std::cout << i;});
}
else
{
std::for_each(first, last, [outforchar](T i){std::cout << i << outforchar;});
}
}
While this function works for types like ints, chars, and strings. It doesn't work for the item class which has a >> operator which formats the input according to the specifications. The compiler throws this error:
./tempsorter.h:14:47: error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
std::for_each(beg, end, [](T i){std::cout << i;});
^
In file included from /usr/include/c++/4.8.2/iostream:39:0,
from psort.cpp:16:
/usr/include/c++/4.8.2/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 = Product]’
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
^
In file included from /usr/include/c++/4.8.2/algorithm:62:0,
from ./tempsorter.h:2,
from psort.cpp:18:
/usr/include/c++/4.8.2/bits/stl_algo.h:4411:5: error: ‘_Funct std::for_each(_IIter, _IIter, _Funct) [with _IIter = const Item*; _Funct = Output(const T*, const T*, char) [with T = Item]::__lambda0]’, declared using local type ‘Output(const T*, const T*, char) [with T = Item]::__lambda0’, is used but never defined [-fpermissive]
for_each(_InputIterator __first, _InputIterator __last, _Function __f)
^
/usr/include/c++/4.8.2/bits/stl_algo.h:4411:5: error: ‘_Funct std::for_each(_IIter, _IIter, _Funct) [with _IIter = const Item*; _Funct = Output(const T*, const T*, char) [with T = Item]::__lambda1]’, declared using local type ‘Output(const T*, const T*, char) [with T = Item]::__lambda1’, is used but never defined [-fpermissive]
I understand this error and can get rid of it using something like:
for (auto i = first; i != last; ++i)
{
std::cout << i;
}
But then this gives me incorrect outputs so I can't use it at all.
I am expected to traverse through the various types with something like the following:
for (typename E::ConsItr i = e.Begin(); i != e.End(); ++i)
I can't seem to understand how to implement this into the function, what am I doing wrong?
First,
[](T const& i){std::cout << i;}
is probably better. In addition, you probably wrote your << operator wrong.
std::ostream& operator<<(std::ostream& os, const SomeType& x)
it should look like that, and possibly be a friend of your type. Ensure it is in the same namespace as your type. Or you overloades >> instead of <<

Is using a reference parameter with default value good practice?

I have the following code:
#include <string>
#include <iostream>
void f(const std::string& s = "")
{
std::cout << "\"" << s << "\"" << std::endl;
}
int main()
{
std::string s1 = "qwe";
f();
f("asd");
f(s1);
}
How bad (if at all) are the calls with the temporary and without the parameters?
As far as I know this compiles only due to the fact that const reference prolongs the life of the temporary until the end of a method http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/
Trying to compile the same example without the const next to s parameter fails.
#include <string>
#include <iostream>
void f(std::string& s = "")
{
std::cout << "\"" << s << "\"" << std::endl;
}
int main()
{
std::string s1 = "qwe";
f();
f("asd");
f(s1);
}
Compilation
g++-5 -O3 -Wall --std=c++11 main.cpp && ./a.out
main.cpp:4:27: error: invalid initialization of non-const reference of type ‘std::string& {aka std::basic_string<char>&}’ from an rvalue of type ‘std::string {aka std::basic_string<char>}’
void f(std::string& s = "")
^
In file included from /usr/include/c++/5/string:52:0,
from main.cpp:1:
/usr/include/c++/5/bits/basic_string.h:2893:7: note: after user-defined conversion: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]
basic_string(const _CharT* __s, const _Alloc& __a = _Alloc());
^
main.cpp: In function ‘int main()’:
main.cpp:12:5: error: invalid initialization of non-const reference of type ‘std::string& {aka std::basic_string<char>&}’ from an rvalue of type ‘std::string {aka std::basic_string<char>}’
f();
^
In file included from /usr/include/c++/5/string:52:0,
from main.cpp:1:
/usr/include/c++/5/bits/basic_string.h:2893:7: note: after user-defined conversion: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]
basic_string(const _CharT* __s, const _Alloc& __a = _Alloc());
^
main.cpp:4:6: note: in passing argument 1 of ‘void f(std::string&)’
void f(std::string& s = "")
^
main.cpp:13:10: error: invalid initialization of non-const reference of type ‘std::string& {aka std::basic_string<char>&}’ from an rvalue of type ‘std::string {aka std::basic_string<char>}’
f("asd");
^
In file included from /usr/include/c++/5/string:52:0,
from main.cpp:1:
/usr/include/c++/5/bits/basic_string.h:2893:7: note: after user-defined conversion: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]
basic_string(const _CharT* __s, const _Alloc& __a = _Alloc());
^
main.cpp:4:6: note: initializing argument 1 of ‘void f(std::string&)’
void f(std::string& s = "")
It's not a horrible practice, but it's generally better to provide overloads:
void f(std::string const& s) { std::cout << "\\" << s << "\\\n"; }
void f() { f(""); }
It avoids some language features that end up being confusing to many people. For example, what does this print?
struct base { virtual void f(int i = 42) { std::cout << i; } };
struct derived : base { void f(int i = 19) { std::cout << i; }};
int main() { base * b = new derived(); b->f(); }
There are also ambiguity errors that can come up when you're using default parameters that don't when you use overloads.
As far as const references in particular, that doesn't really matter much. The default value binds to reference for the lifetime of the function call. It has no effect at all really. You might get better results using values sometimes when the compiler can perform certain optimizations that are not possible with reference parameters, but generally it's not something to be concerned with.
Of course, this doesn't work with non-const references because they don't bind to temporaries.
The default value is for allowing you to call function without any arguments, so use reference parameter with default value if you sometimes will not pass argument to function, otherwise there is no matter to do so.

Operator<< for std::string

I define the operator<< for std::string objects:
std::string & operator<< (std::string & left, std::string & right){
return left += right;
}
Then I use it:
std::string t1("t1"), t2("t2"), t3;
t3 = t2 << t1;
And get from a compiler:
t.cpp: In function 'int main()':
t.cpp:44:28: error: no matching function for call to 'operator<<(std::string&, std::string&)'
t.cpp:44:28: note: candidates are:
In file included from d:\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/iostream:40:0,
from connection.h:10,
from login.cpp:1:
d:\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/ostream:600:5: note: template<class _CharT, class _Traits, class _Tp> std::basic_ostream<_CharT
, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&)
d:\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/ostream:600:5: note: template argument deduction/substitution failed:
t.cpp:44:28: note: 'std::string {aka std::basic_string<char>}' is not derived from 'std::basic_ostream<_CharT, _Traits>'
In file included from d:\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/iostream:40:0,
Why talks it about ostream and does not talk about string? I.e. why it does not take in account my definition of the operator<< ?
Thanks.
Update. For those who is able just to say "why do you create operator<< for strings?" and is not able to say any helpful things:
std::string & operator<< (std::string & left, const int num){
return left += std::to_string(num);
}
std::string t3;
t3 << 3 << 5;
std::cout << t3 << std::endl;
And log:
t.cpp: In function 'int main()':
t.cpp:45:12: error: no match for 'operator<<' in 't3 << 3'
t.cpp:45:12: note: candidates are:
In file included from d:\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/iostream:40:0,
from connection.h:10,
from login.cpp:1:
d:\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/ostream:600:5: note: template<class _CharT, class _Traits, class _Tp> std::basic_ostream<_CharT
, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&)
d:\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/ostream:600:5: note: template argument deduction/substitution failed:
t.cpp:45:12: note: 'std::string {aka std::basic_string<char>}' is not derived from 'std::basic_ostream<_CharT, _Traits>'
It does work:
#include <iostream>
#include <string>
std::string & operator<< (std::string & left, std::string & right){
return left += right;
}
int main()
{
std::string t1("t1"), t2("t2"), t3;
t3 = t2 << t1;
std::cout << t3;
}
Output: t2t1 [GCC 4.8.1]
The compiler output, as you say yourself, indicates that your operator overload is not even visible. You must not have your declaration in the right place.
This is not really a good idea, anyway: you will simply confuse the heck out of anybody who reads your code. Strings are not streams.