Error compiling vtkStringToken with ABI namespacing
With gcc, and perhaps other compilers, the following recent code fails to compile unless VTK_NO_ABI_NAMESPACE
is defined:
namespace std
{
VTK_ABI_NAMESPACE_BEGIN
/// vtkStringTokens provide a specialization of std::hash so they can be used in unordered
/// containers.
template <>
struct VTKCOMMONCORE_EXPORT hash<vtkStringToken>
{
std::size_t operator()(const vtkStringToken& t) const { return t.GetId(); }
};
VTK_ABI_NAMESPACE_END
} // namespace std
The error is due to the nested namespaces (click for error log)
In file included from VTK/Common/Core/vtkStringManager.h:27,
from VTK/Common/Core/vtkStringManager.cxx:15:
VTK/Common/Core/vtkStringToken.h:208:29: error: specialization of ‘template<class _Tp> struct std::hash’ in different namespace [-fpermissive]
208 | struct VTKCOMMONCORE_EXPORT hash<vtkStringToken>
| ^~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/9/bits/basic_string.h:6727,
from /usr/include/c++/9/string:55,
from /usr/include/c++/9/bits/locale_classes.h:40,
from /usr/include/c++/9/bits/ios_base.h:41,
from /usr/include/c++/9/ios:42,
from /usr/include/c++/9/istream:38,
from /usr/include/c++/9/fstream:38,
from VTK/Common/Core/vtkIOStream.h:29,
from VTK/Common/Core/vtkSystemIncludes.h:39,
from VTK/Common/Core/vtkIndent.h:28,
from VTK/Common/Core/vtkObjectBase.h:53,
from VTK/Common/Core/vtkObject.h:45,
from VTK/Common/Core/vtkStringManager.h:26,
from VTK/Common/Core/vtkStringManager.cxx:15:
/usr/include/c++/9/bits/functional_hash.h:58:12: note: from definition of ‘template<class _Tp> struct std::hash’
58 | struct hash;
| ^~~~
In file included from VTK/Common/Core/vtkStringManager.h:27,
from VTK/Common/Core/vtkStringManager.cxx:15:
VTK/Common/Core/vtkStringToken.h:208:29: error: explicit specialization of ‘template<class _Tp> struct std::hash’ outside its namespace must use a nested-name-specifier [-fpermissive]
208 | struct VTKCOMMONCORE_EXPORT hash<vtkStringToken>
| ^~~~~~~~~~~~~~~~~~~~
VTK/Common/Core/vtkStringToken.h:210:51: error: definition of ‘std::size_t std::hash<vtk9::vtkStringToken>::operator()(const vtk9::vtkStringToken&) const’ is not in namespace enclosing ‘std::hash<vtk9::vtkStringToken>’ [-fpermissive]
210 | std::size_t operator()(const vtkStringToken& t) const { return t.GetId(); }
| ^~~~~
make[3]: *** [Common/Core/CMakeFiles/CommonCore.dir/build.make:1952: Common/Core/CMakeFiles/CommonCore.dir/vtkStringManager.cxx.o] Error 1
make[2]: *** [CMakeFiles/Makefile2:15850: Common/Core/CMakeFiles/CommonCore.dir/all] Error 2
make[1]: *** [CMakeFiles/Makefile2:15857: Common/Core/CMakeFiles/CommonCore.dir/rule] Error 2
make: *** [Makefile:2311: CommonCore] Error 2
I recommend adding a new macro VTK_ABI_NAMESPACE_QUALIFIER
that provides a qualifier for the namespace, e.g. vtk9::
, so that we can rewrite this code without nested namespaces:
namespace std
{
/// vtkStringTokens provide a specialization of std::hash so they can be used in unordered
/// containers.
template <>
struct VTKCOMMONCORE_EXPORT hash<VTK_ABI_NAMESPACE_QUALIFIER vtkStringToken>
{
std::size_t operator()(const VTK_ABI_NAMESPACE_QUALIFIER vtkStringToken& t) const
{
return t.GetId();
}
};
} // namespace std
Related: #18775
Edited by David Gobbi