Будет ли указатель на функцию-член шаблона внутри конструктора форсировать создание экземпляров? - PullRequest
2 голосов
/ 20 апреля 2011

Рассмотрим следующий заголовочный файл:

// Foo.h
class Foo {
    public: template <typename T> void read(T& value);
};

Кажется, что присвоение указателя на Foo::read<T> в конструкторе класса, переменная которого затем объявлена, вызывает создание экземпляра:

// Foo.cc
#include "Foo.h"

template <typename T>
void Foo::read(T& value) { /* do something */ }

template <typename T> struct Bar {
    Bar<T>() { void (Foo::*funPtr)(T&) = &Foo::read<T>; }
};

static Bar<int  > bar1;
static Bar<long > bar2;
static Bar<float> bar3;

Является ли это решение надежным / переносимым / соответствующим стандартам?(Это работает, по крайней мере, с компиляторами Intel и GNU.)

Если вам интересно, почему бы просто не использовать template Foo::read<int>(int&); см. этот вопрос .

Ответы [ 3 ]

2 голосов
/ 20 апреля 2011

14.7.1 это где он находится./ 2 говорит:

Если специализация шаблона функции не была явно создана или явно специализирована, специализация шаблона функции создается неявно, когда на специализацию ссылаются в контексте, для которого требуется определение функции.

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

Так что факт, что GCC и Intel создают его, предполагаетчто все остальные должны, так как то, что не требуется, запрещено.При условии, что все согласны, конечно.

2 голосов
/ 20 апреля 2011

Да, ваше решение переносимо.Вот другой способ

template <typename T, T> struct user { };
template <typename T> struct Bar {
    typedef user< void (Foo::*)(T&), &Foo::read<T> > user_type;
};

Теперь, когда неявно создается экземпляр Bar<T>, он неявно создает экземпляр Foo::read<T>.Нет необходимости создавать объект.

1 голос
/ 20 апреля 2011

Когда объекты для Bar<type> объявляются с фактическими типами, тогда определенно, да; будет создан экземпляр Foo::read<type>(). Однако она будет ограничена только этой функцией (скажем, Foo::write<type>() не будет создан).

Иначе, если вы попробуете что-то вроде этого:

template<typename T>
struct X
{
  Bar<T> b1;  // this is required but not sufficient to instantiate Foo::read<T>()
};

Тогда Foo::read<int>() не будет создан, пока вы не объявите X<int>.

Редактировать : В приведенном выше примере прямого объявления Bar<int> b1; (int вместо T) внутри X также НЕ достаточно. Содержащий его тип X<> должен быть создан с фактическим (т.е. не шаблонным) типом.

...