Почему шаблоны не могут быть внутри внешних блоков "C"? - PullRequest
25 голосов
/ 02 февраля 2011

Это дополнительный вопрос к ответу на Можно ли в шаблоне определить тип функции указатель-на-внешний-C?

Этот код не может быть скомпилирован с g++, Visual C / C ++ и Comeau C / C ++ с в основном тем же сообщением об ошибке:

#include <cstdlib>

extern "C" {
    static int do_stuff(int) {
        return 3;
    }

    template <typename return_t_, typename arg1_t_>
    struct test {
        static void foo(return_t_ (*)(arg1_t_)) { }
    };
}

int main()
{
    test<int, int>::foo(&do_stuff);
    return EXIT_SUCCESS;
}

g ++ говорит "ошибка": template with C linkage ", Visual C / C ++ выдает ошибку компилятора C2894 , и Comeau C / C ++ говорит" error: это объявление не может иметь внешнюю связь "C" ".

дело в том, что все довольны:

#include <cstdlib>

extern "C" {
    static int do_stuff(int) {
        return 3;
    }

    struct test {
        static void foo(int (*)(int)) { }
    };
}

int main()
{
    test::foo(&do_stuff);
    return EXIT_SUCCESS;
}

Раздел 7.5, Спецификации связывания, Стандарт C ++ гласит:

Связывание языка AC игнорируется для имен членов класса итип функции-члена функций-членов класса.

И это даже дает пример:

extern "C" {
    class X {
        void mf(); // the name of the function mf and the member
                // function's type have C++ language linkage
        void mf2(void(*)()); // the name of the function mf2 has C++ language
                // linkage; the parameter has type pointer to C function
    };
}

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

Почему тогда глава 14, Шаблоны, оf Стандартное состояние C ++ 98:

Имя шаблона может иметь связь (3.5).Шаблон, явная специализация шаблона (14.7.3) и частичная специализация шаблона класса не должны иметь связи C.

Что означает, что шаблон "может" иметь связь?Что такое связь с шаблоном?

Почему явно запрещено иметь шаблон с связью C, когда с классом все в порядке и все функции-члены экземпляров шаблона (конструктор по умолчанию, деструктор и перегрузка оператора присваивания)) будет иметь связь C ++?

Ответы [ 5 ]

14 голосов
/ 02 февраля 2011

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

10 голосов
/ 02 февраля 2011

Что означает, что шаблон "может" иметь связь?Что такое шаблонная связь?

Все имена либо имеют внешнюю связь, внутреннюю связь, либо не имеют связи (C ++ 03 §3.5p2), но это не та же связь, что и языковая связь.(Я знаю, что это сбивает с толку. C ++ 0x также значительно меняет ситуацию с помощью связывания.) Внешнее связывание требуется для всего, что используется в качестве аргумента шаблона:

void f() {
  struct S {};
  vector<S> v;  // Not allowed as S has internal linkage.
}

Обратите внимание, что в C ++ 98 есть «может»"в том, что вы цитировали в §14p4, но C ++ 03 удаляет" может ", поскольку шаблоны не могут быть объявлены в контексте, который дал бы им внутреннюю связь:

void f() {
  // Not allowed:
  template<class T>
  struct S {};
}
4 голосов

Поскольку extern C отключает искажение имен, какие шаблоны используют

Чтобы увидеть, что шаблоны реализованы с использованием преобразования имен, компилировать и декомпилировать:

#include <cassert>

template <class C>
C f(C i) { return i; }

int main() {
    f<int>(1);
    f<double>(1.5);
}

с помощью:

g++ -c -g -std=c++98 main.cpp
objdump -Sr main.o

Вывод содержит:

int main() {
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 83 ec 10             sub    $0x10,%rsp
    f<int>(1);
   8:   bf 01 00 00 00          mov    $0x1,%edi
   d:   e8 00 00 00 00          callq  12 <main+0x12>
            e: R_X86_64_PC32    _Z1fIiET_S0_-0x4
    f<double>(1.5);
  12:   48 b8 00 00 00 00 00    movabs $0x3ff8000000000000,%rax
  19:   00 f8 3f 
  1c:   48 89 45 f8             mov    %rax,-0x8(%rbp)
  20:   f2 0f 10 45 f8          movsd  -0x8(%rbp),%xmm0
  25:   e8 00 00 00 00          callq  2a <main+0x2a>
            26: R_X86_64_PC32   _Z1fIdET_S0_-0x4
}
  2a:   b8 00 00 00 00          mov    $0x0,%eax
  2f:   c9                      leaveq 
  30:   c3                      retq

Обратите внимание, как все callq были созданы для вызова странных имен, таких как _Z1fIiET_S0_.

То же самое относится и к другимфункции, которые зависят от искажения имени, например перегрузка функций.

Я написал более подробный ответ по адресу: Каково влияние extern "C" в C ++?

3 голосов
/ 02 февраля 2011

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

0 голосов
/ 02 февраля 2011

Потому что в C. нет шаблонов.

...