Статическая переменная в обрабатывает функцию по шаблону

В моем файле машинописи, когда я использую

import moment from 'moment';

, он говорит, что не может найти модуль «момент». Я установил момент в виде пакета npm, и на него ссылаются правильно, но по той причине, что moment.d.ts экспортирует момент как пространство имен, а не модуль, как показано ниже, я не могу ссылаться на него.

export = moment; 

Так что, если я изменю его на

declare module 'moment' {
    export default moment;
}

, импорт будет работать отлично. Что я здесь не так делаю?

27
задан sth 15 June 2009 в 17:59
поделиться

7 ответов

На это можно положиться. ODR (одно правило определения) говорит в 3.2 / 5 в Стандарте, где D обозначает нестатический шаблон функции (курсивный шрифт мной)

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

Из последних четырех требований два наиболее важных примерно

  • каждое определение D должно состоять из одной и той же последовательности токенов
  • имена в каждом определении должны относиться к одним и тем же вещам ("сущностям")

Править

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

Здесь вступает в действие связь . Если имя специализации шаблона функции (которая является функцией) имеет внешнюю связь ( 3.5 / 4 ), то имя, которое относится к такой специализации, относится к той же функции. Для шаблона, который был объявлен статическим, функции, созданные из него, имеют внутреннюю связь, поскольку

Сущности, созданные из шаблона с внутренней связью, отличаются от всех сущностей, сгенерированных в других единицах трансляции. - 14/4

Имя, имеющее область пространства имен (3.3.6), имеет внутреннюю связь, если это имя [...] объекта, ссылки, функции или шаблона функции, которые явно объявлены static - 3.5 / 3

Если шаблон функции не был объявлен с помощью static, то он имеет внешнюю привязку (это, кстати, также является причиной того, что мы должны вообще следовать ODR. В противном случае, D вообще не будет определяться множественно!). Это может быть получено из 14/4 (вместе с 3.5 / 3 )

Шаблон функции, не являющейся членом, может иметь внутреннюю связь; любое другое имя шаблона должно иметь внешнюю ссылку. - 14/4 .

Наконец, мы приходим к выводу, что специализация шаблона функции, сгенерированная из шаблона функции с внешней связью, сама имеет внешнюю связь 3.5 / 4 :

Имя, имеющее область пространства имен, имеет внешнюю связь, если это имя функции, [...] если она не имеет внутренней связи - 3.5 / 4

А когда она имеет внутреннюю связь, поясняется 3.5 / 3 для предоставленных функций явными специализациями и 14/4 для сгенерированных специализаций (экземпляров шаблонов). Поскольку имя вашего шаблона имеет внешнюю связь, все ваши специализации имеют внешнюю связь: если вы используете их имя ( incAndShow ) из разных единиц перевода, они будут ссылаться на одни и те же функции, что означает ваши статические объекты будет одинаковым в каждом случае.

31
ответ дан 28 November 2019 в 05:34
поделиться

Я понимаю ваш вопрос. Вы спрашиваете, нормально ли для каждой версии шаблонной функции иметь собственный экземпляр myStaticVar. (например: incAndShow vs. intAndShow Ответ - да.

Другой вопрос: если два файла содержат заголовок, содержащий функцию шаблона, будут ли они по-прежнему использовать статическую переменную для данного T. Я бы сказал да.

6
ответ дан 28 November 2019 в 05:34
поделиться

Разница при создании шаблона функции состоит в том, что он имеет внешнюю связь. Тот же incAndShow будет доступен из всех единиц перевода.

Перефразирование из рабочего проекта стандарта C ++ N2798 (2008-10-04): 14 часть 4: шаблон функции, не являющейся членом, может иметь внутреннюю связь, другие всегда имеют внешнюю связь. 14.8, пункт 2: каждая специализация будет иметь свою собственную копию статической переменной.

Ваш шаблон функции должен иметь внешнюю связь, если вы не объявите его в безымянном пространстве имен или в чем-то еще. Итак, для каждого T, который вы используете с вашим шаблоном функции, вы должны получить одну статическую переменную, используемую для работы программы. Другими словами, нормально полагаться на наличие только одной статической переменной в программе для каждого экземпляра шаблона (одна для T == int, одна для T == short и т. Д.).

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

3
ответ дан 28 November 2019 в 05:34
поделиться

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

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

Это отличается от non код шаблона.

0
ответ дан 28 November 2019 в 05:34
поделиться
  • шаблоны будут фактически преобразованы в код только после того, как они будут созданы (т. Е. Использованы). Заголовки
  • не должны использоваться для кода реализации, а только для объявлений
-3
ответ дан 28 November 2019 в 05:34
поделиться

Да, это «нормально», но чего бы вы ни пытались достичь с помощью этой «функции», это может быть сомнительно. Попробуйте объяснить, почему вы хотите использовать локальную статическую переменную, может быть, мы сможем придумать более чистый способ сделать это.

Причина, по которой это нормально, заключается в том, как функции шаблона скомпилированы и связаны. Каждая единица перевода (два .cpp в вашем случае) получает собственную копию incAndShow, и когда программа связывается вместе, два incAndShow будут объединены в одну. Если вы объявите свою обычную функцию встроенной в файл заголовка, вы получите аналогичный эффект.

0
ответ дан 28 November 2019 в 05:34
поделиться

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

#include <iostream>

template <class T> class Some
{
public:
   static int stat;
};

template<class T>
int Some<T>::stat = 10;

void main()
{
   Some<int>::stat = 5;
   std::cout << Some<int>::stat   << std::endl;
   std::cout << Some<char>::stat  << std::endl;
   std::cout << Some<float>::stat << std::endl;
   std::cout << Some<long>::stat  << std::endl;
}

Вы получаете: 5 10 10 10 10

Выше показано, что изменение статической переменной предназначено только для введите "int" и, следовательно, в вашем случае вы не увидите никаких проблем.

-1
ответ дан 28 November 2019 в 05:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: