Как работает шаблон Stroustrup Can_Copy? - PullRequest
6 голосов
/ 22 февраля 2011

Stroustrup предоставляет шаблон Can_copy .Как это работает?

template<class T1, class T2> struct Can_copy {
    static void constraints(T1 a, T2 b) { T2 c = a; b = a; }
    Can_copy() { void(*p)(T1,T2) = constraints; }
};

В частности, зачем ему нужна строка void(*p)(T1,T2) = constraints; вместо пустого конструктора?Разрешено ли компиляторам создавать только функции, которые конкретный экземпляр шаблона использует для оптимизации?

Ответы [ 4 ]

8 голосов
/ 22 февраля 2011

Это потому, что неиспользуемые функции-члены в шаблонах не существуют в сгенерированном коде, поэтому для проверки ограничений вам придется явно вызывать constraints() где-нибудь.

Этот код пути для constraints() генерируется, поэтому ограничения проверяются во время компиляции (и это цель Can_copy).

4 голосов
/ 22 февраля 2011

C ++ 03 §14.7.1p1:

Если специализация шаблона класса не была явно создана (14.7.2) или явно специализирована (14.7.3), специализация шаблона класса создается неявно, когда на специализацию ссылаются в контексте, который требует полностью определенного типа объекта или когда полнота типа класса влияет на семантику программы. Неявная реализация специализации шаблона класса вызывает неявную реализацию объявлений, , но не определений или аргументов по умолчанию, функций-членов класса, классов-членов, статических членов-данных и шаблонов элементов; ...

Таким образом, этот код не может создать экземпляр Can_copy :: constraints:

template<class T1, class T2>
struct Can_copy {
  static void constraints(T1 a, T2 b) { T2 c = a; b = a; }
  Can_copy() { /* note the change here */ }
};

template<class Container>
void draw_all(Container& c) {
  typedef typename Container::value_type T;
  Can_copy<T,Shape*>(); // accept containers of only Shape*s
}

Но в исходном коде, когда создается экземпляр ctor Can_copy, как и должно быть, когда он используется, его тело (определение) также хорошо, и это вызывает создание экземпляра Can_copy :: constraints.

Вы можете увидеть эту же проблему в обратном порядке, когда явное создание дает вам все, даже то, что вам не нужно:

typedef std::list<int>::iterator Iter;
std::reverse_iterator<Iter> x;  // Implicit instantiation; works.

template std::reverse_iterator<Iter>;
// Explicit instantiation; fails to instantiate op+ and other operators used
// for random access iterators from reverse_iterator.
3 голосов
/ 22 февраля 2011

Предназначен для того, чтобы быть информативным, а не ответом (не заслуживающим возражений):

В C ++ 0x у вас будут улучшенные возможности для этого в заголовке <type_traits>.

std::is_copy_constructible<T1>::value;
std::is_copy_assignable<T1>::value;
std::is_constructible<T1, T2>::value;
std::is_assignable<T1, T2>::value;
std::is_convertible<T1, T2>::value;

http://www.open -std.org / ОТК1 / SC22 / wg21 / документы / документы / 2010 / n3225.pdf

поиск "[meta]".

2 голосов
/ 22 февраля 2011

Использование шаблона так же просто, как Can_copy<int, char>();

Если экземпляр T1 не может быть скопирован в экземпляр T2, код b = a не будет компилировать вообще. Точно так же, если экземпляр T2 не может быть инициализирован с экземпляром T1, код T2 c = a; не будет компилироваться.

Таким образом, если T1 невозможно скопировать в T2, строка, содержащая использование шаблона, не будет компилироваться.

Вся конструкция не производит (почти) код и легко удаляется оптимизатором.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...