Параметры шаблона по умолчанию с форвардным объявлением
Можно ли переслать объявление класса, который использует аргументы по умолчанию, не указав или не узнав эти аргументы?
Например, я хотел бы объявить boost::ptr_list< TYPE >
в классе "Черты", не перетаскивая всю библиотеку Boost в каждый файл, содержащий черты. Я хотел бы заявить
namespace boost { template<class T> class ptr_list< T >; }
, но это не работает, потому что оно точно не соответствует истинному объявлению класса:
template < class T,
class CloneAllocator = heap_clone_allocator,
class Allocator = std::allocator<void*>
>
class ptr_list { ... };
Могут ли мои варианты жить с ним или указать boost::ptr_list< TYPE, boost::heap_clone_allocator, std::allocator<void*>
в моем классе свойств? (Если я использую последний, мне также придется переслать declare boost::heap_clone_allocator
и включить <memory>
, я полагаю.)
Я просмотрел книгу Страуступа, ТАК, и остальную часть Интернета и не нашел решения. Обычно люди обеспокоены тем, что не включают STL, и решение "просто включает заголовки STL". Тем не менее, Boost - это гораздо более массивная библиотека, насыщенная компиляторами, поэтому я бы предпочел оставить ее, если только мне это не нужно.
Ответы
Ответ 1
Любая единица компиляции, которая использует ваше средство, которое передает объявления вперед, должно включать в себя заголовки форматирования в любом случае, за исключением случаев, когда у вас есть определенные программы, которые фактически не будут использовать дополнительную часть вашего объекта.
Верно, что путем форвардного объявления вы можете избежать включения заголовков boost для таких программ. Но вам придется вручную включать заголовки boost (или иметь #ifdef
) для тех программ, которые фактически используют часть boost.
Имейте в виду, что в будущем выпуске Boost можно добавить дополнительные параметры шаблона по умолчанию. Я бы посоветовал против этого маршрута. Что я хотел бы рассмотреть, если ваша цель - ускорить время компиляции, - это использовать #define
, чтобы указать, должен ли быть отключен код, использующий эту библиотеку boost. Таким образом, вы избегаете трудностей, связанных с выражением.
Ответ 2
Да. Аргументы шаблона по умолчанию могут быть указаны в любое время и в любом месте, если объявления не конфликтуют друг с другом. В конечном итоге они объединяются из различных деклараций.
Даже это законно:
template< class A, class B, class C = long >
class X;
template< class A, class B = int, class C >
class X;
template< class A = short, class B, class C >
class X { };
Аналогичный пример приведен в §14.1/10. Согласно этому параграфу, аргументы по умолчанию по умолчанию ведут себя аналогично.
Удачи в том, чтобы заставить декларацию вести себя, а не на всех!
Ответ 3
Я не думаю, что вы можете переслать объявление шаблона с аргументами по умолчанию, если только соответствующая библиотека не предоставила свой собственный заголовок прямого объявления. Это связано с тем, что вы не можете реагировать на аргументы по умолчанию (даже если они совпадают... gcc все равно сообщает "ошибка: переопределение аргумента по умолчанию" ).
Итак, насколько мне известно, решение заключается в том, чтобы библиотека предоставляла заголовок прямого заголовка Foo_fwd.h:
#ifndef INCLUDED_Foo_fwd_h_
#define INCLUDED_Foo_fwd_h_
template<class T, class U=char> class Foo; // default U=char up here
#endif
а затем полная реализация в Foo.h будет:
#ifndef INCLUDED_Foo_h_
#define INCLUDED_Foo_h_
#include "Foo_fwd.h"
template<class T, class U> class Foo { /*...*/ }; // note no U=char here
#endif
Итак, теперь ваш код может также использовать Foo_fwd.h... но, к сожалению, поскольку этот подход требует модификации исходного Foo.h, чтобы удалить аргументы по умолчанию, это не масштабируется для сторонних библиотек. Возможно, нам следует лоббировать команду С++ 0x, чтобы разрешить эквивалентное исправление аргументов шаблона по умолчанию, à la typedefs...?
Ответ 4
Ну, такая же проблема здесь. Но с STL.
Если один из моих заголовков использует, например. std::vector, тогда я должен включить весь заголовок. С этого момента каждый раз, когда я включаю заголовок, даже если мой исходный код не ссылается на std::vector, заголовок включается вместе с моим заголовком. Если вы включите этот заголовок во много места, это будет означать много переусердства.
Итак, я перенаправил объявленный std::vector и использовал std::vector *, но мой код не хочет компилироваться из-за аргументов по умолчанию. Если я поместил аргументы по умолчанию в свой заголовок, тогда компилятор откажется компилировать заголовок stl из-за уважения аргументов по умолчанию.
В этой ситуации я пытаюсь создать свой собственный класс Vector, который адаптирует std::vector и переадресует каждый вызов метода на него. Вероятно, это может решить проблему.