user2485710
user2485710

Reputation: 9801

Why I need C++ linkage for a template?

Sometimes I try to follow the logic of some rules, sometimes the logic of why things are happening the way they do defeats any law that I know of.

Typically a template it's described as something that lives only during the compilation phase and it's exactly equivalent to hand-writing some function foo for any given type T .

So why this code doesn't compile ( I'm using C++11 with gcc and clang at the moment but I don't think it's that relevant in this case ) ?

#include <iostream>
#include <cstdint>
#include <cstdlib>
extern "C" {
template <typename T>
T foo(T t)
{
    return t;
}
}
int main()
{
    uint32_t a = 42;
    std::cout << foo(a) << '\n';
    return EXIT_SUCCESS;
}

And the thing that defeats all the logic is that the complain is about the linkage, and the implicit message is that this code doesn't generate a function, it generates something else that after compilation it's not suitable for a C style linkage.

What is the technical reason why this code doesn't compile ?

Upvotes: 0

Views: 578

Answers (3)

Galik
Galik

Reputation: 48615

Well other answers have explained why it doesn't work from the C++ side.

From the C side there are work-rounds but they are not portable.

You can simply not use the extern "C" keyword, create name-mangled functions and then in the C code link to the actual mangled names.

To make that easier you could also use GCC's abi::__cxa_demangle() function combined with a look-up table so you don't need to know what the mangled function names are (just their demangled signature).

But it all a bit of a bodge really.

Of course if you only call the template functions from C code, they'll never get instantiated to begin with. So you would need to make sure they get called in the C++ code to make sure they're present in the object file.

Upvotes: 0

Bill Lynch
Bill Lynch

Reputation: 81926

Let's look at this from a simple perspective. At the very least, using extern "C" will remove the C++ name mangling. So, we then have your template, and we'll instantiate it twice.

int foo(int val);
float foo(float val);

Under C's naming rules, these are required to have the same name foo from the perspective of the linker. If they have the same name though, we can't distinguish between them, and we'll have an error.

Under C++, the rules for how names are mangled is implementation defined. So C++ compilers will apply a name mangling to these two functions to differentiate them. Perhaps we'll call them foo_int and foo_float.

Because C++ can do this, we have no issues. But extern "C" requires the compiler to apply the C naming rules.

Upvotes: 14

Sneftel
Sneftel

Reputation: 41474

"linkage" is a slightly misleading term. The main thing that extern "C" changes is name mangling. That is, it produces symbol names in the object files that are compatible with the sort of symbols that equivalent C code would produce. That way it can link with C object code.... but it's a different sort of thing than specifying static or extern linkage.

But templates don't have a C equivalent, and name mangling is used to make sure that different instantiations of a given templated function result in different symbol names (so that the linker knows which one to use in a given place).

So there's no way to give templates C linkage; you're asking the compiler to do two fundamentally incompatible things.

Upvotes: 3

Related Questions