2010-07-27 2 views
5

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

Я знаю о внешней связи с использованием ключевого слова

extern "C" 

EX:

extern "C" { template<class T> class X { }; } 

, но они дали шаблона не должен иметь C связи

что на самом деле означал для вышеупомянутое заявление?

Может ли кто-нибудь объяснить это?

+5

Я только что заметил, что вы добавили щедрость за вопрос. Кажется странным, поскольку я считаю, что ответ, который я дал, был правильным и полным. Что вы еще не понимаете? - Я заметил, что вы также удалили начальную часть вопроса, сделав большую часть ответа бесполезным ... Вы должны рассмотреть возможность добавления комментариев или другого вопроса, если у вас все еще есть проблемы. Изменение вопроса не помогает никому - люди, которые уже ответили, не получают уведомления, люди, просматривающие q и a, будут сбиты с толку ответами, которые не освобождены ... –

+0

Вернулся к версии перед удалением, так что это имеет смысл , – Suma

+0

@David: Похоже, что BE Student заинтересован в выдаче очков специально для USER. –

ответ

2

extern "C" используется для изменения имени символа функции C++, чтобы использовать их из программы C.

В C++ прототип функции «закодирован» в имени символа, это требование перегрузки. Но в C у вас нет такой функции.

extern «C» позволяет вызывать функцию C++ из программы C.

extern "C" не то, что вы ищете.

Не могли бы вы объяснить, что вы хотите сделать?

+0

@Apatrice: Мне нужно объяснение вышеуказанной точки – 2010-07-27 08:10:35

+0

См. Http://en.wikipedia.org/wiki/Name_mangling#Handling_of_C_symbols_when_linking_from_C.2B.2B –

7

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

Описание того, что соединительное средство находится в п.3.5/2, в частности, внешняя связь определяется как:

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

Чтобы заставить внутреннюю увязку функции, не являющихся членами шаблона вы можете использовать static ключевое слово, но вы не можете сделать то же самое с другими шаблонами:

template <typename T> 
static void foo(T) {} 

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

Внутренняя связь: § 3.5/2

Когда имя имеет внутреннюю связь, то оно обозначает лицо может называться по именам из других областей в одной и той же единице трансляции.

Обратите внимание, что разница в том, что он не может быть передан из других единиц перевода.

namespace { 
    template <typename T> 
    class test {}; 
} 

Пока безымянные имена не делают связь внутренними, она гарантирует, что не будет никакого столкновения имени, как это будет в уникального пространства имен. Эта уникальность гарантирует, что код недоступен из других единиц перевода. Без имени Пространство имен считаются лучшей альтернативой для ключевого слова static §7.3.1.1/2

Использование статического ключевого слова является устаревшим при объявлении объектов в области видимости пространства имен (приложение D); неназванный-имен обеспечивает превосходную альтернативу

С другой стороны, когда вы говорите, что вы:

знать о внешней связи, используя ключевое слово extern "C"

Вы не делаете. extern "C" не является запросом на внешнюю связь. Перечитайте спецификацию. extern "C" - это спецификация связи и инструктирует компилятор использовать связь стиля «C» внутри блока, чтобы взаимодействовать с C-кодом или библиотеками, которые уже работают таким образом, как dlopen и семьей. Это описано в §7.

2

Ответ на обновленный вопрос, как я уже сказал в ответе, который относится к исходному вопросу, означает, что вы не понимаете, что означает extern "C".

Последовательность extern "X" позволяет изменить язык связь следующей функции или блока языка X. Это не средних внешних связей, поэтому исходная предпосылка:

Я знаю о внешней связи с использованием ключевого слова extern "C"

является ложным. Вы не знаете, что это значит. См. 7.5 в стандарте. Языковая связь влияет на то, как компилятор обрабатывает параметры и применяет ли он (и, возможно, как) имя к символам.

Отвлекая вашу настойчивость в этой конкретной ошибке, компилятор жалуется на ваш код, поскольку он недействителен в соответствии со стандартом. В частности, §14 [temp]/4:

Название шаблона имеет связь (3.5). Шаблон функции, не являющийся членом, может иметь внутреннюю связь; любое другое имя шаблона должно иметь внешнюю связь. Объекты, созданные из шаблона с внутренней связью, отличаются от всех объектов, сгенерированных в других единицах перевода. Шаблон, специализированная специализация шаблона (14.7.3) или частичная специализация шаблона шаблона не должны иметь C-ссылки. Если связь одного из них является чем-то отличным от C или C++, поведение определяется реализацией. Определения шаблонов должны соответствовать одному правилу определения (3.2).[Примечание:. По умолчанию аргументы для шаблонов функций и для функций-членов шаблонов класса рассматриваются определения для целей шаблона конкретизации (14.5), а также должны соблюдать правила по одному определению]

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

23

extern "C" заявляет, что есть C языковая связь. Это отличается от внешняя связь и внутренняя связь. По умолчанию все в программе на C++ имеет связь на языке C++, хотя вы можете повторить это, указав extern "C++".

внешняя связь означает, что это имя видно другим исходным файлам, скомпилированным отдельно, при условии, что вы включаете правильные заголовки или указываете правильные объявления. Это то, что позволяет определить функцию foo в a.cpp и называть ее от b.cpp. Большинство имен в области пространства имен в программе на C++ имеют внешнюю связь. Исключением являются те, которые имеют внутренняя связь, а те, которые имеют , не связаны. Вы можете явно отметить что-то как внешнее соединение, указав extern. Это отличается от extern "C".

внутренняя связь означает, что имя уникально для текущего блока компиляции, и вы не можете получить доступ к переменной или функции из другого исходного файла. Переменные и функции области видимости файла static имеют внутреннюю связь. Кроме того, const целые переменные в области пространства имен, которые инициализируются константным выражением, по умолчанию имеют внутреннюю привязку, хотя вы можете переопределить ее с явным extern.

И, наконец, локальные переменные и классы имеют нет связи. Имена локальны для функции, в которой они объявлены, и к ней нельзя получить доступ извне этой функции. Вы можете использовать extern, чтобы указать, что вы действительно хотите получить доступ к переменной в области пространства имен.

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

int i; // namespace scope variable has external linkage 
extern int j; // explicitly mark j with external linkage 
static int k; // k has internal linkage 
int const n=42; // internal linkage 
extern int const m=99; // external linkage 

void foo(); // foo has external linkage; it may be defined in this source file or another 
extern void foo(); // explicitly mark foo with external linkage 
static void bar(); // bar has internal linkage, and must be defined in this source file 

void foo(){} // definition of foo, visible from other source files 
void bar(){} // definition of bar, not visible from other source files (internal linkage) 

static void baz(){} // declare and define baz with internal linkage 

template<typename T> void foobar(){} // foobar has external linkage 
template<typename T> 
static void foobaz(){} // foobaz has internal linkage 

void wibble() 
{ 
    int i; // local, no linkage 
    extern int i; // references i, declared above with external linkage 
} 

extern "C" 
{ 
    int i2; // namespace scope variable has external linkage, and "C" linkage 
    extern int j2; // explicitly mark j2 with external linkage and "C" linkage 
    static int k2; // k2 has internal linkage and "C" linkage 
    int const n2=42; // internal linkage and "C" linkage 
    extern int const m2=99; // external linkage and "C" linkage 

    void foo2(); // foo2 has external linkage and "C" linkage 
    static void bar2(); // bar2 has internal linkage and "C" linkage 

    void foo2(){} // definition of foo2, still with external linkage and "C" linkage 
    void bar2(){} // definition of bar2, still with internal linkage and "C" linkage 

    static void baz(){} // declare and define baz with internal linkage 
} 

Сообщение об ошибке правильно --- шаблоны не могут иметь extern "C" связи.

На базовом уровне шаблоны не могут иметь связи extern "C", потому что они несовместимы с C. В частности, шаблон не просто определяет один класс или функцию, а семейство классов или функций, которые имеют одно и то же имя , но отличаются их параметрами шаблона.

Только одна функция с заданным именем может быть объявлена ​​extern "C". Это имеет смысл, если вы думаете об изменении имени --- в C, функция foo обычно называется либо foo, либо _foo в таблице символов.В C++ может быть много перегрузок foo, поэтому подпись включена в «искаженное» имя в таблице символов, и вы можете получить $3fooV или foo$void или что-то еще, чтобы отличить foo(void) от foo(int) и так далее. В C++ единственная перегрузка, которая отмечена extern "C", получает искалечен согласно схеме C для данной платформы, тогда как другие перегрузки сохраняют свое обычное искаженное имя.

Объявление шаблона extern "C" требует всей инстанциации быть extern "C", что, таким образом, противоречит «только одна функции с заданным именем может быть extern "C"» правилом.

Хотя C не имеет названия для struct s, может быть только один struct с заданным именем. Таким образом, запрет на extern "C" для шаблонов классов имеет смысл --- шаблон определяет семейство классов с тем же именем, что соответствует C struct?

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