How to fix compilation error with gcc8 while specializing swap function/ - c++

I'm trying to compile code which specialize the function std::swap for my class.
But I'm facing an issue that occurs because of rvalue constructor (it works when I comment the line)
I am compiling with g++ (GCC) 8.2.1 20180905 (Red Hat 8.2.1-3)
and g++ -std=c++14 -Wall those options
#include <iostream>
#include <utility>
namespace ns1
{
class Foo
{
public:
Foo();
Foo(const Foo& that) {};
Foo(Foo&& that) {}; // <--- work when commented
~Foo();
void swap(Foo &that) {};
};
inline void swap(Foo &lhs, Foo &rhs)
{
lhs.swap(rhs);
}
} // namespace ns1
namespace std {
template <>
inline void swap(ns1::Foo &lhs, ns1::Foo &rhs)
{
lhs.swap(rhs);
}
} // namespace std
I have the following error message :
error: template-id 'swap<>' for 'void std::swap(ns1::Foo&, ns1::Foo&)' does not match any template declaration
inline void swap(ns1::Foo &lhs, ns1::Foo &rhs)
^~~~
In file included from /opt/rh/devtoolset-8/root/usr/include/c++/8/string:52,
from /opt/rh/devtoolset-8/root/usr/include/c++/8/bits/locale_classes.h:40,
from /opt/rh/devtoolset-8/root/usr/include/c++/8/bits/ios_base.h:41,
from /opt/rh/devtoolset-8/root/usr/include/c++/8/ios:42,
from /opt/rh/devtoolset-8/root/usr/include/c++/8/ostream:38,
from /opt/rh/devtoolset-8/root/usr/include/c++/8/iostream:39,
from toto.cpp:1:
/opt/rh/devtoolset-8/root/usr/include/c++/8/bits/basic_string.h:6276:5: note: candidates are: 'template<class _CharT, class _Traits, class _Alloc> void std::swap(std::basic_string<_CharT, _Traits, _Alloc>&, std::basic_string<_CharT, _Traits, _Alloc>&)'
swap(basic_string<_CharT, _Traits, _Alloc>& __lhs,
^~~~
In file included from /opt/rh/devtoolset-8/root/usr/include/c++/8/bits/stl_algobase.h:64,
from /opt/rh/devtoolset-8/root/usr/include/c++/8/bits/char_traits.h:39,
from /opt/rh/devtoolset-8/root/usr/include/c++/8/ios:40,
from /opt/rh/devtoolset-8/root/usr/include/c++/8/ostream:38,
from /opt/rh/devtoolset-8/root/usr/include/c++/8/iostream:39,
from toto.cpp:1:

The error you are seeing is because providing a user defined move-constructor prevents compiler from synthesizing move-assignment operator, therefore making your class non move-assignable.
As per cppreferece, T in swap must be move-assignable.
To fix it, provide move-assignment operator as well, demo
Foo& operator=(Foo&& other) {return *this;}
Foo& operator= (const Foo& other) { return *this; }
Also take a look at rule of five

Maybe instead of extending std it should be better to rely on ADL+using std::swap;.
Your example is very similar to this guideline.
(http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c165-use-using-for-customization-points)
Another guideline tells that we should prefer overload to template
specialisation
(http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#t144-dont-specialize-function-templates)
but unfortunately it is undefined behavior in std
(https://en.cppreference.com/w/cpp/language/extending_std)

Related

Why does libstdc++ implement both <L,R> and <LR> overloads for binary operators on iterators?

In libstdc++3, in the header bits/stl_iterator.h (GCC 10 source here), every binary operator for __normal_iterator has two overloads defined (here is == for example):
template<typename _IteratorL, typename _IteratorR, typename _Container>
_GLIBCXX20_CONSTEXPR
inline bool
operator==(const __normal_iterator<_IteratorL, _Container>& __lhs,
const __normal_iterator<_IteratorR, _Container>& __rhs)
_GLIBCXX_NOEXCEPT
{ return __lhs.base() == __rhs.base(); }
template<typename _Iterator, typename _Container>
_GLIBCXX20_CONSTEXPR
inline bool
operator==(const __normal_iterator<_Iterator, _Container>& __lhs,
const __normal_iterator<_Iterator, _Container>& __rhs)
_GLIBCXX_NOEXCEPT
{ return __lhs.base() == __rhs.base(); }
Where .base() returns a pointer to an array element in this case. This is done throughout the library for other iterator types as well. According to comments and changelogs scattered throughout, it's done to support interoperability between iterators and const_iterators.
My question is, why are both the the <_IteratorL, _IteratorR, _Container> and <_Iterator, _Container> overloads defined for all of them? That is, why is <_Iterator, _Container> necessary? Wouldn't the former cover every case? What would break if the latter was removed?
GCC's libstdc++ implementation has a lot of street cred, so I'm sure there's a good, possibly subtle reason, but I can't figure out what it could be.
I ask because I'm currently working out some kinks in my own custom iterator implementations and looking at the STL as a model.
The comment above that complains about std::rel_ops, which provide a template<class T> bool operator!=(const T& lhs, const T& rhs).
Reducing __normal_iterator to it's bare essentials to show the problem, we get this:
#include <utility>
template<typename T>
struct normal_iterator {
T m_base;
const T& base() const { return m_base; }
};
// (1)
template<typename IteratorL, typename IteratorR>
bool operator!=(const normal_iterator<IteratorL>& lhs, const normal_iterator<IteratorR>& rhs) {
return lhs.base() != rhs.base();
}
// (2)
template<typename Iterator>
bool operator!=(const normal_iterator<Iterator>& lhs, const normal_iterator<Iterator>& rhs) {
return lhs.base() != rhs.base();
}
int main() {
using namespace std::rel_ops;
// Your container's `const_iterator` is `const int*`, and `iterator` is `int*`
normal_iterator<const int*> a{nullptr};
normal_iterator<int*> b{nullptr};
a != b; // Uses (1) to compare const_iterator and iterator
a != a; // Uses (2) to compare two iterators
}
Without the second overload, this would not compile since there are two viable functions to call:
std::rel_ops::operator!=<normal_iterator<int*>>(const normal_iterator<int*>&, const normal_iterator<int*>&)
operator!=<int*, int*>(const normal_iterator<int*>&, const normal_iterator<int*>&)
And neither is more specialiased than the other (it is ambiguous)
For std::rel_ops specifically, there is no reason for the extra == overload, but nothing is stopping a user from writing a similar template<typename T> bool operator==(const T&, const T&) in some other namespace.

deleted friend declaration declares a non-template function

I want to delete a specific overloaded friend function in a class.
The below code compiles, and works in the way intended.
However, I get the following warning (g++, c++11,14,17):
edit: Warning is present using gcc9.3 and older, but not for gcc10
warning: friend declaration 'bool operator==(const MyType<BaseT>&, const BaseT&)' declares a non-template function [-Wnon-template-friend]
6 | friend bool operator==(const MyType<BaseT> &lhs, const BaseT &rhs) = delete;
| ^~~~~~
new.cpp:6:72: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
Can someone shed light on the warning? Why does it apply for the deleted function, but not the implemented one?
template <typename BaseT> struct MyType {
BaseT v;
explicit MyType(BaseT tv) : v(tv) {}
explicit operator BaseT() const { return v; }
friend bool operator==(const MyType<BaseT> &lhs, const BaseT &rhs) = delete;
friend bool operator==(const MyType<BaseT> &lhs, const BaseT &&rhs) {
return lhs.v == rhs;
}
};
int main(){
MyType<int> a{3};
int b{3};
// a==b; //Fails to compile: good. Do not allow comparisons between different types
a==3; //Compiles fine: good. Allow literal comparison, without implicit constructor
}

"no match" and "cannot bind lvalue" errors while overloading `operator<<` with `std::wostream` and `std::string`

I've got an error while overloading std::wostream::operator<<() for std::string.
Here is the minimal test case illustrating my problem:
#include <string>
#include <sstream>
inline std::wostream &operator<<(std::wostream &os, const std::string &)
{
return os;
}
class FakeOstream{};
namespace mynamespace {
class FakeClasse1 {
friend inline FakeOstream &operator<<(FakeOstream &out, const FakeClasse1 &) {
return out;
}
};
class FakeClasse2 {
friend inline FakeOstream &operator<<(FakeOstream &out, const FakeClasse2 &) {
return out;
}
};
void test()
{
auto mystring = std::string{u8"mystring"};
std::wostringstream s;
s << mystring; // The errors occur here
}
} // namespace mynamespace
The code can be compiled and executed here: http://cpp.sh/9emtv
As you can see here, there is an overload for operator<< with std::wostream
and std::string. The two fake classes are empty apart from the declaration of
an operator<< with FakeOstream and themselves. The test() function
instantiate an std::wostringstream and feed it a std::string. The fake
fake classes and test function are in a namespace.
This code yields the following error on cpp.sh at the line s << mystring;:
In function 'void mynamespace::test()':
25:10: error: cannot bind 'std::basic_ostream<wchar_t>' lvalue to 'std::basic_ostream<wchar_t>&&'
In file included from /usr/include/c++/4.9/istream:39:0,
from /usr/include/c++/4.9/sstream:38,
from 2:
/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 = wchar_t; _Traits = std::char_traits<wchar_t>; _Tp = std::basic_string<char>]'
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
^
When using directly g++ (version 5.3.0 from MSYS2), a no match error is also
displayed:
./tmpbug.cpp: In function 'void mynamespace::test()':
./tmpbug.cpp:25:7: error: no match for 'operator<<' (operand types are 'std::wostringstream {aka std::__cxx11::basic_ostringstream<wchar_t>}' and 'std::__cxx11::basic_string<char>')
s << mystring;
^
In file included from C:/Appli/msys64/mingw64/include/c++/5.3.0/istream:39:0,
from C:/Appli/msys64/mingw64/include/c++/5.3.0/sstream:38,
from ./tmpbug.cpp:2:
C:/Appli/msys64/mingw64/include/c++/5.3.0/ostream:628:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = wchar_t; _Traits = std::char_traits<wchar_t>; _Tp = std::__cxx11::basic_string<char>] <near match>
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
^
C:/Appli/msys64/mingw64/include/c++/5.3.0/ostream:628:5: note: conversion of argument 1 would be ill-formed:
./tmpbug.cpp:25:10: error: cannot bind 'std::basic_ostream<wchar_t>' lvalue to 'std::basic_ostream<wchar_t>&&'
s << mystring;
^
In file included from C:/Appli/msys64/mingw64/include/c++/5.3.0/istream:39:0,
from C:/Appli/msys64/mingw64/include/c++/5.3.0/sstream:38,
from ./tmpbug.cpp:2:
As far as I know, all the parts of the example are necessary for the errors to
appear. If I comment out the namespace, the fake classes or just one of the
operator<< in the fake classes, the code compile just fine. Moreover, if I
just move one of the fake classes or the test function outside of the namespace,
the code will also compile just fine.
Additionnally, I tried compiling this example on clang 3.7 by using the compiler
from http://cppreference.com, and the code seems to compile without problems.
Is there a problem with my code or is this a GCC bug ? If this is a GCC bug, is
there a workaround ?
This is a bad idea:
inline std::wostream &operator<<(std::wostream &os, const std::string &)
as you should not overload operators on two types in std that do not depend on your own (outside of std or build-in) types. Doing ... doesn't work well. And, in my opinion, shouldn't be allowed.
Regardless, you can generate the same problem with conforming code by simply creating your own namespace notstd and own type notstd::string, then in the global root namespace defining
inline std::wostream &operator<<(std::wostream &os, const notstd::string &)
{
return os;
}
and get the same symptoms. So that doesn't matter much.
Operators are found first via unqualified name lookup, then via argument dependent lookup.
As we have no using statement, unqualified name lookup first looks in the enclosing namespace. If nothing is found, the namespaces containing it (and eventually the file/global namespace) are then searched.
ADL then augments this with operators found via ADL or Koenig lookup -- it looks in the namespaces of the arguments and their template parameters.
Now, the friend operator<< you defined do live in the namespace their class contains, but they are usually difficult to find.
Somehow your double-declaration of friend operator<< is making your code find them, and stop looking into the global namespace for a <<.
To me this looks like a bug. Neither of those "Koenig operators" should be visible to bog-standard unqualified name lookup with types unrelated to the classes they are "contained" in.
MCVE:
#include <iostream>
#include <sstream>
namespace notstd {
struct string {};
}
inline void operator<<(std::wostream &os, const notstd::string &){ return; }
class FakeOstream{};
namespace mynamespace {
class UnusedClass1 {
friend inline void operator<<(FakeOstream &out, const UnusedClass1 &) { return; }
};
class UnusedClass2 {
// comment this line out and the code compiles:
friend inline void operator<<(FakeOstream &out, const UnusedClass2 &) { return; }
};
void test() {
auto mystring = notstd::string{};
std::wostringstream s;
s << mystring; // The errors occur here
}
} // namespace mynamespace
int main(){}
live example.
#T.C. found what appears to be this bug being fixed:
test code
fix in gcc

Implicit cast doesn't work for BOOST_STRONG_TYPEDEF and BOOST_SPIRIT_DEBUG_NODE

I have defined a boost::spirit::qi rule:
boost::spirit::qi::rule<Iterator, Identifier()> id;
where Identifier is defined by:
BOOST_STRONG_TYPEDEF(std::string, Identifier)
but when I use
BOOST_SPIRIT_DEBUG_NODE(id);
It fails to compile with following error:
boost_1_51_0/boost/spirit/home/support/attributes.hpp:1203: error: no match for 'operator<<' in 'out << val'
and it lists the overloaded operators of ostream.
Knowing that BOOST_STRONG_TYPEDEF defines a cast operator to the original type, shouldn't
compiler implicitly cast from Identifier to std::string when using operator<<? or is there a restriction that prevents compiler to apply a cast operator of a type when it is trying to match the other operator (namely operator<< )?
When I define the following operator it compiles:
inline std::ostream& operator<<(std::ostream& os, const Identifier& id)
{
return os << static_cast<std::string const&>(id);
}
I am using gcc4.4.2
This has nothing to do with boost, strong_typedef or spirit.
It has a lot to do with type deduction for template arguments. In short, when argument types are deduced, implicit conversions never take place [1]
Cf.:
#include <iostream>
#include <string>
#include <boost/strong_typedef.hpp>
BOOST_STRONG_TYPEDEF(double, X)
int main() { std::cout << X(); }
No problem! Replace double by std::string, and it doesn't work anymore. What's different?
The declaration of the streaming operator differs.
Contrast
ostream& ostream::operator<<(double);
To
template<typename _CharT, typename _Traits, typename _Alloc>
inline basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>&, basic_string<_CharT, _Traits, _Alloc> const&)
The fact that the operator overload is a function template disallows any implicit conversions.
[1] I guess initializer_list may look like a bit of an exception here, what with widening/narrowing that it can do. Different subject, though

Some compiler errors concerning an overloaded operator on a template in c++

I have some code with a few errorr I do not understand how to fix at all. I have asked my professor and TA, and consulted the internet with no luck, apart from understanding more precisely what the errors mean. From what I can tell, the compiler is either confusing my overloaded operator with built in operators, or it is not recognizing it as an overloaded operator at all.
I am getting the following errors and warnings:
||=== project 4, Debug ===|
\project 4\forest.h|13|warning: friend declaration 'Forest<NODETYPE>& operator+(Forest<NODETYPE>&, Forest<NODETYPE>&)' declares a non-template function|
\project 4\forest.h|13|note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) |
\project 4\forest.h|14|warning: friend declaration 'std::ostream& operator<<(std::ostream&, const Forest<NODETYPE>&)' declares a non-template function|
\project 4\forest.h|15|warning: friend declaration 'std::istream& operator>>(std::istream&, Forest<NODETYPE>&)' declares a non-template function|
\project 4\main.cpp||In function 'int main()':|
\project 4\main.cpp|21|error: ambiguous overload for 'operator>>' in 'file >> intForest'|
c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\istream|119|note: candidates are: std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::operator>>(std::basic_istream<_CharT, _Traits>& (*)(std::basic_istream<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>] <near match>|
c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\istream|123|note: std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::operator>>(std::basic_ios<_CharT, _Traits>& (*)(std::basic_ios<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>] <near match>|
c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\istream|130|note: std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::operator>>(std::ios_base& (*)(std::ios_base&)) [with _CharT = char, _Traits = std::char_traits<char>] <near match>|
||=== Build finished: 1 errors, 3 warnings ===|
When I try to compile my code. The relevant code segments are as follows:
(in forest.h)
template< typename NODETYPE > class Forest
{
public:
friend Forest<NODETYPE>& operator+(Forest<NODETYPE>&, Forest<NODETYPE>&);
friend ostream& operator<<(ostream&, const Forest<NODETYPE>&);
friend istream& operator>>(istream&, Forest<NODETYPE>&);
Forest();
Forest( const Forest& otherForest);
~Forest();
void nodes(int&) const;
private:
ForestNode<NODETYPE> *root;
ForestNode<NODETYPE> *getNewNode( const NODETYPE &);
};
(in forest.cpp)
template<typename NODETYPE> istream& operator>>(istream& file, const Forest<NODETYPE>& f1)
{
istream file2 = file;
int nodeCount = 0;
string blah = ' ';
while(getline(file2,blah))
{
nodeCount++;
}
ForestNode<NODETYPE> *forestNodeArray[nodeCount];//holds pointers to last node of depth i
getline(file,*f1.root.tag);
forestNodeArray[0] = &(*f1.root);
inputHelper(file, 0, *f1.root, forestNodeArray, nodeCount);
return file;
}
(and finally, in main.cpp)
int main()
{
Forest < char > intForest();
filebuf fb;
fb.open ("forest1.txt",ios::in);
istream file(&fb);
cout << typeid(intForest).name() << endl;
cout << typeid(file).name() << endl;
file >> intForest;
fb.close();
}
Any help would be greatly appreciated.
EDIT: Thanks to alex and alf, I understand why they were not considered template functions. It's quite obvious in retrospect, I was just set on those signatures. Anyway, I still get the error about the ambiguous operator. Why does the compiler not recognize my operator and use it, instead of trying to decide between 3 built in versions of the operator that could not possibly have one parameter as Forest?
The second error is in this line:
Forest < char > intForest();
This may be surprising at first, but that line is not declaring a variable of type Forest<char>, but rather a function that takes no arguments and returns a Forest<char>.
Just remove the parenthesis from the declaration:
Forest < char > intForest;
On the first warning, which is already explained (the function declared as friend is not a template, and that means that you will manually have to implement it for each type you use to instantiate Forest<> with (probably you don't want that). Also note that declaring the templated operator+ and then making the template a friend as in #Alf P. Steinbach answer means that a Forest<int> will be a friend of a Forest<double>, which might not be what you need. #Alex proposal in the comment will only make a particular instantiation of the template a friend, which is probably closer to what you want, but you need to declare the templated operator before the template class, and for that you will need to forward declare the template class...
A common pattern for friend free functions in templates is defining the function in place:
template <typename T>
class Forest {
// ...
friend Forest& operator+( Forest const & lhs, Forest const & rhs ) [1]
{
// implementation here
}
}
// [1] Note that the arguments are const references (read only), and also note that
// you do not need to provide the type argument inside the template declaration
This allows you to define it as a non templated function and at the same time have the compiler instantiate the function for you. Also, it is usually simpler to also define member methods inlined in the class definition when dealing with templates. It makes life simpler, and after all in most cases you do need to provide the implementation in the (same) header file.
Yet, when defining binary operators a better approach is to define operator+= as a member method, and then you can easily define operator+ as a non-friend free function. The pattern would be:
struct test {
test& operator+=( test const & );
};
test operator+( test lhs, test const & rhs ) { // [2]
lhs += rhs;
return lhs;
}
// [2] Note that the first argument is by value, and the second by const reference
// This means that the compiler will copy the first argument for you, and you
// are free to modify it with the += operator and return the copy.
Now, the most tricky part is mixing the previous two advices. To be able to define operator+ that is a free function inside the template definition, a common trick is to make it friend even if that is not required for access reasons:
template <typename T>
class Forest {
Forest& operator+=( Forest const & ) {
// implemenation
}
friend Forest operator+( Forest lhs, Forest const & rhs ) { // [3]
return lhs+=rhs;
}
};
// [3] friendship only to allow us to define the free function inside the template
// declaration.
The (first) warning tells you that the befriended function is not a template.
And it isn't.
Think about how you would implement it. It would entail writing one such function for each possible NODE_TYPE.
There are several ways to fix that.
One way is to befriend a function template, like so:
template< class Type >
struct S
{
template< class U > friend void foo( S<U> );
};
template< class Type >
void foo( S< Type > x ) {}
int main()
{}
Cheers & hth.,
learning C++,I also encountered the same problem.But I had solved it for another way!
template <class NODETYPE> class Forest;
template <class NODETYPE> Forest<NODETYPE>& operator+ (Forest<NODETYPE>&, Forest<NODETYPE>&);
template <class NODETYPE> ostream& operator<<(ostream&, const Forest<NODETYPE>&);
template <class NODETYPE> istream& operator>> (istream&, Forest<NODETYPE>&);
template<class NODETYPE>
template< typename NODETYPE >
class Forest
{
public:
friend Forest<NODETYPE>& operator+ <>(Forest<NODETYPE>&, Forest<NODETYPE>&);
friend ostream& operator<< <>(ostream&, const Forest<NODETYPE>&);
friend istream& operator>> <>(istream&, Forest<NODETYPE>&);
Forest();
Forest( const Forest& otherForest);
~Forest();
void nodes(int&) const;
private:
ForestNode<NODETYPE> *root;
ForestNode<NODETYPE> *getNewNode( const NODETYPE &);
};