2013-07-08 2 views
7

В следующей программе «Здесь» печатается:C++ статические переменные без ссылок класса

#include <iostream> 
class Base 
{ 
    static bool temp; 
    static bool initTemp() 
    {std::cout<<"Here\n";return true;} 
}; 

bool Base::temp = Base::initTemp(); 

class Derived : public Base 
{}; 

int main() {int a;std::cin>>a;} 

В следующей программе «Здесь» не печатается:

#include <iostream> 
template <class T> 
class Base 
{ 
    static bool temp; 
    static bool initTemp() 
    {std::cout<<"Here\n";return true;} 
}; 

template <class T> 
bool Base<T>::temp = Base<T>::initTemp(); 

class Derived : public Base<int> 
{}; 

int main() {int a;std::cin>>a;} 

В обоих случаях база никогда ссылки. Единственное различие заключается в том, что во втором случае это шаблонный класс. Может ли кто-нибудь объяснить мне, почему это происходит. Я использую VS 2012.

+2

'void main()' не является законным C++. Должно быть 'int main()'. –

+0

Во втором примере «Здесь» печатается, если вы явно создаете статический член: 'template bool Base :: temp;' – willj

ответ

6

В обоих случаях база никогда не ссылается.

И именно по этой причине вы не видите ничего, что печатается на стандартном выходе.

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

Это указано в пункте 14.7.1/1 C++ 11 Стандарт на:

[...] неявной конкретизацией шаблона класса специализации вызывает неявную экземпляров деклараций, но не от определений или аргументов по умолчанию, от функций-членов класса, классов-членов, облачных имен элементов, статических данных-членов и шаблонов-членов. [...]

Поскольку ваш код клиента никогда не ссылается на Base<>::temp, его не нужно создавать и инициализировать.


Как примечание стороны, эта подпись:

void main() 

не действительны (стандарт) C++. Если вы хотите написать переносимый код, возвращаемый тип main() всегда должен быть int.

+0

Но код содержит 'класс Derived: Base ' ... (почему) не делает этого как экземпляр? –

+0

Я отредактировал сообщение так, чтобы он использовал int. Есть ли способ создать экземпляр класса, наследуя его? то есть есть ли способ автоматически инициализировать temp для многих разных производных типов без необходимости писать шаблон <> bool Base :: temp = Base :: initTemp(); –

+0

@KonradRudolph: «* Неявное создание экземпляра специализации шаблона вызывает неявное экземпляры деклараций, но не определений или аргументов по умолчанию, функций-членов класса, классов-классов , перечислений членов, статических данных и Шаблоны членов * "(14.7.1/1) –

-3

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

template <class T> 
bool Base<T>::temp = Base<T>::initTemp(); 

Вы не можете выделить переменную неопределенного типа. Что вам нужно написать что-то вроде:

Base<int>::temp = value; 

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

Для downvoters Вот полный пример:

#include <iostream> 

template<class T> 
class X 
{ 
public: 
    static int v; 
}; 

template<class T> 
int X<T>::v = 0; 

int main() 
{ 
    X<int>::v = 3; 
    X<char>::v = 2; 

    using namespace std; 
    cout << X<char>::v << endl << X<int>::v; 
} 

Он печатает 2 3, который означает, что вы не можете иметь одну переменную для всех классов, которые вы будете создать экземпляр шаблона.

+1

Вы абсолютно можете. –

+0

Я думаю, что Богтол имел в виду, что для каждого другого instanstiation X вы будете иметь другое значение v. Это правда, но я хочу иметь другое значение v для каждого экземпляра. Чтобы разделить одну и ту же статическую переменную среди всех экземпляров, X должен наследовать от некоторого базового класса, отличного от шаблона, который содержит v. –

+0

Пример вашего кода на самом деле показывает, что вы * можете * делать то, что вы утверждаете, что не можете делать. –

2

В первом случае, вы не создаете экземпляр Base, но вы называете статической функции:

bool Base::temp = Base::initTemp(); 

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

template <class T> 
bool Base<T>::temp = Base<T>::initTemp(); 

Вы может явно создать шаблон класса Base, как с:

template class Base<int>; 

И тогда вы увидите «Здесь».

+0

ОК, это круто, я не знал, что форвард объявляет класс шаблона. –

+1

@BenjyKessler: Это не форвардное объявление, это явное инстанцирование –

+0

@BenjyKessler: lol, да, отредактировал комментарий. Мой мозг спит –

Смежные вопросы