Why Can't Templates Be Within Extern "C" Blocks

Why can't templates be within extern C blocks?

What does it mean that a template "may" have linkage? What is template linkage?

All names either have external linkage, internal linkage, or have no linkage (C++03 §3.5p2), but this is not the same linkage as language linkage. (Confusing, I know. C++0x changes things around considerably with linkage, too.) External linkage is required for anything used as a template argument:

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

Notice that C++98 has "may" in what you quoted of §14p4, but C++03 removes the "may", as templates cannot be declared in a context that would give them internal linkage:

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

How to make a function with C-linkage from template?

The only restriction on templates is that the name cannot have C linkage, there is no restriction on its type, so you can use a typedef for a C linkage function in the first declaration of the template.

extern "C" typedef void cfunc();
template <typename T> cfunc yourfunc;
template <typename T> void yourfunc() { }

Using templates to get rid of dynamic linking boilerplate: extern C and templates don't mix;

  1. Should this template using directive actually compile? (It does on clang but not gcc)

I'm not sure. The standard says that function types, function names and variable names have a language linkage, but it doesn't say whether you can use an alias template to produce such function types.

EDG rejects it too, but Clang might be correct to allow it.

Edit: I failed to find http://open-std.org/JTC1/SC22/WG21/docs/cwg_closed.html#1463 which points out [temp]/4 says

A template, a template explicit specialization (14.7.3), and a class template partial specialization shall not have C linkage.

So technically Clang is wrong to accept it, but the Evolution Working Group are going to consider whether it should be allowed.


  1. If I declare my function pointer type as: extern "C" typedef void* (*factory_pointer)(); and cast the return value explicitly with a reinterpret_cast<>, will I be invoking undefined behavior?

(Edit: I originally said yes here, because I misread the question)

No, but a static_cast would be better than reinterpret_cast.


  1. Do I have any other options I might not have considered for accomplishing my stated goal that don't involve void*?

Get rid of all the C language linkage. I don't think it's necessary or useful for your situation.


  1. Is a typedef with extern "C" for the function pointer strictly necessary? The standard can't seem to make up its mind. It says for example: in 7.5 of the 2014 draft standard: "Two function types with different language linkages are distinct types even if they are otherwise identical." but in 8.3.5 paragraph 8: "The return type, the parameter-type-list, the ref-qualifier, and the cv-qualifier-seq, but not the default arguments (8.3.6) or the exception specification (15.4), are part of the function type."

That doesn't say anything about language linkage, so doesn't contradict the very clear statement in 7.5 which says it is part of the type.

Also note:

[expr.call]/1: Calling a function through an expression whose function type has a language linkage that is different from the language linkage of the function type of the called function’s definition is undefined (7.5).

That's undefined because it would not work if for example C language linkage implies a different calling convention to C++ language linkage.

But most compilers will do the right thing because they don't actually use different calling conventions for C and C++ functions, and most don't even implement the rule that the types of functions with C language linkage are different. See e.g. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=2316

Templates external linkage does't work

temp_1.cpp doesn't produce any code because template is compiled for the implementations, the only class the compiler can find for the main is in temp_2.cpp.

That's why you don't get any error.

It is somehow can be compared to a macro: the template class is like the #define, the implementations is like using the macro in the code, at the end of the cpp the "macro" is undefined, only the implementations of it are left.

EDIT:

As I wrote above, the template itself doesn't generate any type, that's why it can't be linked. the type definition is when you use the teplate with a typedef or variable declaration.

for example: template<class T> class vector is a template class, it doesn't make any type definition and doesn't produce any code.

When you use it : vector<int> vInt; or typedef vector<int> vInt_t the class will compiled only for class T=int if you use it again for other type it will be compiled again for that type too.

only used templated type may have a linkage, means it will be the same type when you define it again. the type vector<int> may have external linkage, (means can be return from library or dll, etc.)

What is the effect of extern C in C++?

extern "C" makes a function-name in C++ have C linkage (compiler does not mangle the name) so that client C code can link to (use) your function using a C compatible header file that contains just the declaration of your function. Your function definition is contained in a binary format (that was compiled by your C++ compiler) that the client C linker will then link to using the C name.

Since C++ has overloading of function names and C does not, the C++ compiler cannot just use the function name as a unique id to link to, so it mangles the name by adding information about the arguments. A C compiler does not need to mangle the name since you can not overload function names in C. When you state that a function has extern "C" linkage in C++, the C++ compiler does not add argument/parameter type information to the name used for linkage.

Just so you know, you can specify extern "C" linkage to each individual declaration/definition explicitly or use a block to group a sequence of declarations/definitions to have a certain linkage:

extern "C" void foo(int);
extern "C"
{
void g(char);
int i;
}

If you care about the technicalities, they are listed in section 7.5 of the C++03 standard, here is a brief summary (with emphasis on extern "C"):

  • extern "C" is a linkage-specification
  • Every compiler is required to provide "C" linkage
  • A linkage specification shall occur only in namespace scope
  • All function types, function names and variable names have a language linkage See Richard's Comment: Only function names and variable names with external linkage have a language linkage
  • Two function types with distinct language linkages are distinct types even if otherwise identical
  • Linkage specs nest, inner one determines the final linkage
  • extern "C" is ignored for class members
  • At most one function with a particular name can have "C" linkage (regardless of namespace)
  • extern "C" forces a function to have external linkage (cannot make it static) See Richard's comment: static inside extern "C" is valid; an entity so declared has internal linkage, and so does not have a language linkage
  • Linkage from C++ to objects defined in other languages and to objects defined in C++ from other languages is implementation-defined and language-dependent. Only where the object layout strategies of two language implementations are similar enough can such linkage be achieved

extern c template instantiation

int f_int(int val) = f<int>; is not valid(legal) C++ syntax. The correct syntax to instantiate the function template and return the result of calling that instantiated function with val as argument would look something like:

template<typename T> // my templated function
T f(T val){
return val;
}

extern "C"{
int f_int(int val) {return f<int>(val);} // this does not compile, but this is what I want to achieve
}

Demo



Related Topics



Leave a reply



Submit