Подтвердить что ты не робот

Почему шаблоны не могут находиться внутри внешних блоков "C"?

Это следующий вопрос для ответа на Можно ли ввести typedef в указатель-на-extern- Тип "C" в шаблоне?

Этот код не компилируется с помощью g++, Visual C/С++ и Comeau 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++ говорит "error: template with C linkage", Visual C/С++ испускает ошибку компилятора C2894, а Comau C/С++ говорит: error: эта декларация может не иметь ссылку "C" extern.

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

#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 игнорируется для имен членов класса и функции-члена тип функций класса.

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

extern "C" {
    class X {
        void mf(); // the name of the function mf and the member
                // function 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" , то функции-члены экземпляров будут иметь ссылку на С++.

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

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

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

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

4b9b3361

Ответ 1

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

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

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

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

void f() {
  // Not allowed:
  template<class T>
  struct S {};
}

Ответ 2

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

Ответ 3

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

Ответ 4

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

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

#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_.

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

Смотрите также: fooobar.com/questions/10890/...

Ответ 5

Поскольку в C не существует шаблонов.