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.
Related
Please, help me understand what's wrong with this piece of code:
#include <string>
#include <utility>
class Sample
{
public:
explicit Sample(std::string data):
_data(std::move(data))
{}
operator const std::string &() const & { return _data; }
operator std::string &&() && { return std::move(_data); }
private:
std::string _data;
};
int main()
{
auto sample1 = Sample{"a"};
const auto sample2 = Sample{"b"};
auto sample3 = Sample{"c"};
auto s1 = std::string{sample1};
auto s2 = std::string{sample2};
auto s3 = std::string{std::move(sample3)};
return 0;
}
The problem is with s3. The compiler says sth like that:
<source>: In function 'int main()':
<source>:27:45: error: call of overloaded 'basic_string(<brace-enclosed initializer list>)' is ambiguous
27 | auto s3 = std::string{std::move(sample3)};
| ^
In file included from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/string:55,
from <source>:1:
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:565:7: note: candidate: 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]'
565 | basic_string(basic_string&& __str) noexcept
| ^~~~~~~~~~~~
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:456:7: note: candidate: 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]'
456 | basic_string(const basic_string& __str)
| ^~~~~~~~~~~~
Compiler returned: 1
As I understand, both of the operators for some reason participate in overload resolution for an rvalue. Why is that happening? Should ref-qualifiers leave only one overload for lvalue and the other for rvalue? Am I missing something?
A few other notes:
The behaviour is different across different compilers/versions. I tested it with godbolt and here is what I found:
gcc 8.3 and older - compiles fine
gcc 8.4 and newer - fails to compile
clang - I couldn't find a version where it compiles
MSVC - compiles fine on newest versions
if I refactor operators to normal member functions, it all works as intended
Thank You for Your time, looking forward to any replies :)
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.
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).
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 <<
I have the following code and get the error later described how do i correct this?
The objective behind is to parse the following sentence into variables :
temp1+temp2=10
Code:
int main()
{
string line,var1;
int limit,len;
//some code here
// parse function declarartion :string parse(string ,char ,int &)
f1>>line;
len=line.length();
var1=parse(line,'+',limit);
line.copy(line,len-limit,limit);
//some code here
}
Error:
alice.cpp: In function ‘int main()’:
alice.cpp:65:40: error: no matching function for call to ‘std::basic_string<char>::copy(std::string&, int, int&)’
alicebob.cpp:65:40: note: candidate is:
/usr/include/c++/4.6/bits/basic_string.tcc:724:5: note: std::basic_string<_CharT, _Traits, _Alloc>::size_type std::basic_string<_CharT, _Traits, _Alloc>::copy(_CharT*, std::basic_string<_CharT, _Traits, _Alloc>::size_type, std::basic_string<_CharT, _Traits, _Alloc>::size_type) const [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>, std::basic_string<_CharT, _Traits, _Alloc>::size_type = unsigned int]
/usr/include/c++/4.6/bits/basic_string.tcc:724:5: note: no known conversion for argument 1 from ‘std::string {aka std::basic_string<char>}’ to ‘char*’
If you just want to copy a substring into another string, why don't you use substr() instead?
int main()
{
std::string line("ceva5");
std::string var1;
int limit = 1,len;
//some code here
// parse function declarartion :string parse(string ,char ,int &)
// f1>>line;
len=line.length();
//
// var1=parse(line,'+',limit);
line = line.substr(limit, len-limit);
//some code here
std::cout << line << std::endl;
}
This should do what you want.
EDIT: I have not implemented your function but changed the code to work as string's copy().
Here is the explain: http://www.cplusplus.com/reference/string/string/copy/ ,The first arg is char*, So,Accroding to your question,I think your code should be
line.copy((char *)line.c_str(),len-limit,limit); // wrong code, lost the const
but this code is dangerous,Because std::copy()'s first arg is an array of characters to store the string 's substring, So,I think you code has something wrong.
Here is simple code:
std::string test1 = "test1";
char buffer[10] = {0};
test1.copy(buffer,2,3);
std::cout << "buffer is: " << buffer << std::endl;
and the output is :"buffer is: t1".