Был вполне заурядный кусок кода:
namespace nmea
{
struct DefaultPolicy
{
static bool IsAllowed(const char*, size_t)
{
return true;
}
// ....
};
template<typename Policy=DefaultPolicy>
struct NmeaProcessor
{
bool Parse(IFieldReceiver* receiver)
{
// ....
return true;
}
bool Accumulate(const char* data, size_t size)
{
// ....
return true;
}
};
} // namespace nmea
struct LocalPolicy
{
static bool IsMessageAllowed(const char* data, size_t size)
{
return size >= 80 && !strncmp(data + 3, "TLL", sizeof "TLL" )
&& nmea_utils::IsCSGood(data);
}
};
void foo(IDataSource* data_src, IFieldReceiver* receiver_ptr)
{
nmea::NmeaProcessor<LocalPolicy> processor;
while(IChunkProcessor::Instance()->ReadData(buf, size) )
{
processor.Accumulate(buf, size);
}
processor.Parse(receiver_ptr);
}
По эстетическим соображениям очень хотелось локальную политику определить там, где она используется, чтобы не размазывать код по всему файлу:
void foo(IDataSource* data_src, IFieldReceiver* receiver_ptr)
{
struct LocalPolicy
{
static bool IsMessageAllowed(const char* data, size_t size)
{
return size >= 80 && !strncmp(data + 3, "TLL", sizeof "TLL" ) && nmea_utils::IsCSGood(data);
}
};
nmea::NmeaProcessor<LocalPolicy> processor;
while(IChunkProcessor::Instance()->ReadData(buf, size) )
{
processor.Accumulate(buf, size);
}
processor.Parse(receiver_ptr);
};
Результат получился вполне ожидаемый:
....\parser.cpp(121): error C2926: 'foo::LocalPolicy' : types with no linkage cannot be used as template arguments
Собственно, это не история, а только прелюдия к ней...
Я подоспел уже к "шапочному" разбору, когда народ начал называть компилятор не очень приличными словами, поскольку он не позволяет написать то, что требуется.
Ссылка на стандарт только подбавила масла в огонь, пришлось предложить "бытовую" гипотезу, доступную на "кухонном" уровне:
- С++ обеспечивает типобезопасную компоновку
- Следовательно, при инстанцировании шаблона пользовательским типом его сигнатура должна быть частью сигнатуры порожденного класса, чтобы обеспечить соблюдение ODR (one definition rule)
- А вот для этого тип-параметр шаблона должен иметь эту самую сигнатуру, единую для всех единиц трансляции, то есть иметь ту самую внешнюю компоновку, что требуется стандартом (или что-то ей эквивалентное, но зачем?)
Разговоры о том, что при использовании в качестве параметра шаблона компоновка класса должна становиться внешней, пришлось оборвать, объяснив, что поведение любой системы должно быть консистентным - если, дописывая новый кусок кода, абсолютно не затрагивающий старый, мы можем изменить его семантику (например, при известном везении и совпадении имен) программа может перестать линковаться из-за внезапного появления нового класса в поле зрения компоновщика, то это есть "не айс". Я не прав?
BTW, так что c "тягой к прекрасному" пришлось ограничиться внесением LocalPolicy в анонимный namespace :-)
Комментариев нет:
Отправить комментарий