c++language-lawyerlinkageextern-c

Is it legal to declare a function template of type which has C language linkage?


Function templates are not allowed to have C language linkage:

extern "C" {
    template<typename T>   // error: template with C linkage
    void bad_f() {}
}

This is reasonable, as there are potentially multiple instantiations, but, without name mangling, only one symbol that can be exported at the binary level.

However both GCC and Clang accept function templates with non-template C language linkage type:

extern "C" {
    using F = void();
}

template<typename T>
F f;

template<typename T>
void f() {}

This is surprising to me. It seems reasonable to assume that, analogously to non-template case, instantiations of f have names with C++ language linkage (i.e. name mangling happens) and types with C language linkage (i.e. C calling convention is used to call them).

Is f declaration actually well-formed C++? If so, does it do what I assume it does?


Solution

  • This is CWG1463. The restriction in question doesn't make a lot of sense for several reasons:

    1. language linkage is described as being a property of functions and variables whose names have external linkage (which for extern "C" is name mangling) and of function types (which is calling convention), and a function template is neither of those things ([temp.pre]/6 notwithstanding)
    2. we can't possibly want to give each specialization of a function template (which is not a function whose name has external linkage anyway) C language linkage because (as mentioned) there is only one unmangled name
    3. alias templates could benefit from "having" C language linkage for the function types in their definition and do not have any other potential meaning for it

    Your declaration of f is almost an example of the last point: it can very well be useful to use a template to manufacture C-compatible functions (used by function pointers in C), but the trick of declaring one with a type alias works only in the special case that the function type is not dependent.

    As such, we have (finally) written a paper (link live in December) that has been approved (but not yet applied) as a Defect Report: it removes the questionable rule entirely, letting the function types in template declarations have C language linkage, as well as formally prohibiting

    template<class> extern "C++" void f();
    

    (which implementations have always rejected) so that we can one day specify that that syntax overrides the function-type language linkage implied by an enclosing, say, extern "Java" if such ever becomes widespread.