如何在专门使用交换功能时修复 gcc8 的编译错误/

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

本文关键字:gcc8 编译 错误 功能 交换      更新时间:2023-10-16

我正在尝试编译专门化函数 std::swap 的代码。 但是我面临着由于右值构造函数而发生的问题(当我评论该行时它有效(

我正在使用 g++ (GCC( 8.2.1 20180905 (Red Hat 8.2.1-3( 进行编译 和 g++ -std=c++14 -Wall 这些选项

#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

我有以下错误消息:

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:

您看到的错误是因为提供用户定义的移动构造函数会阻止编译器合成移动赋值运算符,从而使您的类不可移动赋值。 根据 cppreferece,swap中的T必须是可移动分配的。

要修复它,请提供移动赋值运算符,演示

Foo& operator=(Foo&& other) {return *this;}
Foo& operator= (const Foo& other) { return *this; }

也看看五法则

也许与其扩展std不如依靠 ADL+using std::swap;
您的示例与本指南非常相似。
(http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c165-use-using-for-customization-points(

另一个指南告诉我们,我们应该更喜欢重载而不是模板 专业化
(http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#t144-don't-specialize-function-templates(但不幸的是,
它在std
中是未定义的行为(https://en.cppreference.com/w/cpp/language/extending_std(