Конструктор статического члена шаблона С++ не вызывается

У меня есть два тестовых примера класса, имеющего экземпляр статического члена. В первом используются образцы без шаблонов, а во втором используются общие типы объектов.

Дилемма проста: конструктор статического члена вызывается перед основной функцией (как и должно быть), но только для определенных типов объектов. Универсальные типы не демонстрируют такого же поведения. На самом деле конструктор вообще не компилируется. Кажется, компилятор решил совсем проигнорировать его как средство (не совсем оправданное) оптимизации.

Я хотел бы знать, что происходит и что можно сделать, чтобы это работало максимально элегантно. Я предполагаю, что очевидным ответом будет: используйте этот статический член где-нибудь в коде. Я бы не хотел этого делать, поскольку случай конкретного типа работает без использования этого статического члена, кроме выполнения некоторой «работы» в его конструкторе.

Примеры кода:

//////////////////////////////////////////////
// Specific case
//////////////////////////////////////////////
class CPassive
{
public:
    CPassive()
    {
        printf(" passively called ");
    }
};

class CActive
{
private:
    static CPassive ms_passive;
};
CPassive CActive::ms_passive;
///////////////////////////////////////////////////////////
// GENERIC TYPES
///////////////////////////////////////////////////////////
class CSample
{
public:
    CSample()
    {
        printf("sample ");
    }
};

template <typename T>
class CGenericPassive
{
public:
    CGenericPassive()
    {
        T sample;
        printf(" generic passive .. ");
    }
private:
};

template <typename T>
class CGenericActive
{
private:
    static CGenericPassive<T> ms_passive;
};
template<typename T>
CGenericPassive<T> CGenericActive<T>::ms_passive;

int main(int argc, char** argv)
{
    CActive activeExample;// instantiates the static member
    CGenericActive<CSample> activeExample; // obliterates the static from the class def.
}

person teodron    schedule 20.02.2014    source источник
comment
Наверное, я не совсем понимаю. Для универсальных типов, сколько версий класса вы ожидаете запустить, и почему вы ожидаете, что будут работать именно эти версии, а не бесконечное число? например, CGenericPassive<int> CGenericActive<int>::ms_passive; и CGenericPassive<char***> CGenericActive<char***>::ms_passive; И что вы подразумеваете под удалением статики из класса?   -  person m24p    schedule 20.02.2014
comment
В чем проблема? Этот код не делает то, что вы думаете? Что выводит этот код? В частности, что делает этот код, на что вам нужно настроить свое образование?   -  person Dan    schedule 20.02.2014
comment
@Dan шаблонный статический член должен быть явно указан в нешаблонной функции, чтобы он был создан, тогда как обычная статика этого не делает. Я получил ответ, указывающий на это, но он кажется хакерским или как будто в правилах С++ есть причуда.   -  person teodron    schedule 20.02.2014
comment
Вы так и не определили в чем проблема. Есть проблема? Для записи члены не создаются. Классы есть. Если вы не вызываете функцию-член, тогда нет необходимости в ее существовании. Если вы не специализировали шаблон, то в существовании этой специализации шаблона нет необходимости. Но код для создания экземпляра ДОЛЖЕН быть сгенерирован, если и когда создается экземпляр класса.   -  person Dan    schedule 20.02.2014
comment
Я действительно определил, в чем проблема (но вопрос длинный и полон примеров кода, поэтому на первый взгляд он может показаться скучным и запутанным). Короче говоря: почему этот статический член создается/конструируется только для нешаблонных классов, но не для шаблонного, даже если создается объект этого типа контейнерного класса? Не было тривиально очевидным, что этот элемент будет отброшен компилятором (каким правилам следовал компилятор: отбрасывается неиспользуемый напрямую код шаблона?). Спасибо!   -  person teodron    schedule 20.02.2014
comment
Члены НЕ создаются. ПЕРИОД. Покажите мне, что выводит эта программа и какими, по вашему мнению, должны быть результаты.   -  person Dan    schedule 21.02.2014
comment
@Dan См. ответ nm ниже, ideone.com/Y31PJA, в частности, полный живой пример. Закомментируйте ссылку на элемент (void)ms_passive из этого конструктора, и вы увидите, что конструктор CGenericPassive вообще не будет вызываться, тогда как того же самого не произойдет, если используются нешаблонные члены. Я очень устал, когда писал лексическую единицу экземпляра члена. Имейте в виду, я не единственный, кто злоупотребляет выражением: publib.boulder.ibm.com/infocenter/comphelp/v8v101/ .   -  person teodron    schedule 21.02.2014


Ответы (1)


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

Это регулируется стандартом 14.7.1/2:

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

В вашем случае достаточно сослаться на элемент из конструктора CGenericActive (очевидно, вам нужно написать этот конструктор), например:

CGenericActive()
 {
   // just reference it so it gets instantiated
   (void)ms_passive;
 }

Полный живой пример.

person n. 1.8e9-where's-my-share m.    schedule 20.02.2014
comment
Спасибо! Это обходной путь, который я тоже пробовал, но он казался хакерским. Я предполагаю, что мне придется делегировать больше логики статическому члену, чтобы он функционировал более прозрачно и надежно, чтобы не смущать стороннего программиста. Кстати: есть ли какое-либо правило С++, определяющее такое поведение? То же, что и для шаблонного кода: если он нигде не используется, он (очевидно) не будет сгенерирован и скомпилирован? (потому что интуитивно так кажется, даже если конструктор класса члена выполняет некоторую работу, которая не должна быть оптимизирована). - person teodron; 20.02.2014
comment
Добавлена ​​ссылка на стандартную главу и стих. - person n. 1.8e9-where's-my-share m.; 20.02.2014