Sla*_*lav 1 c++ gcc templates c++20
这是使用以下命令编译的数据序列化程序gcc 11.1:
#include <fstream>
#include <ranges>
#include <concepts>
#include <map>
using namespace std;
void write( fstream & f, const integral auto & data ) {
f.write( (const char*)&data, sizeof( data ) );
}
void write( fstream & f, const pair<auto,auto> & p ) {
write( f, p.first );
write( f, p.second );
}
template< ranges::range T >
void write( fstream & f, const T & data ) {
const uint64_t size = ranges::size( data );
write( f, size );
for ( const auto & i : data )
write( f, i );
}
int main() {
auto f = fstream( "spagetti", ios::out | ios::binary );
const bool pls_compile = true;
if constexpr (pls_compile) {
write( f, pair< int, int >( 123, 777 ) );
write( f, map< int, int >{ { 1, 99 }, { 2, 98 } } );
}
else
write( f, pair< map< int, int >, int >( { { 1, 99 }, { 2, 98 } }, 777 ) );
}
Run Code Online (Sandbox Code Playgroud)
这使我成为序列化库的快乐开发人员,该库提供序列化以归档任何integral || pair || range. 但事实证明,如果你设置了pls_compile = false,那么编译就会失败并显示spagetti.cpp:12:10: error: no matching function for call to 'write(std::fstream&, const std::map<int, int>&)'. 它不能通过移动write( pair )过去的声明来修复write( range ),因为pls_compile = true届时将停止编译。
修复它的最佳方法是什么?为什么编译器在生成基于模板的实现时会忘记的存在?显然应该已经熟悉了,因为它已经进行到了。write( range )write( pair< map, int > )write( pair )write( range )write( pair< map, int > )
为了使函数参与重载决策,必须在编译单元中的使用点之前声明该函数。如果直到使用点之后才声明它,则即使编译已经进行到定义点之后才声明它也不会是可能的重载(例如,如果使用是在声明之前定义但触发的模板的实例化)之后使用模板,就像您在这里一样。)
最简单的解决方法是转发声明您的模板/函数。在文件顶部声明所有内容是不会出错的:
void write( fstream & f, const integral auto & data );
void write( fstream & f, const pair<auto,auto> & p );
template< ranges::range T >
void write( fstream & f, const T & data );
Run Code Online (Sandbox Code Playgroud)