Multiple Definition of Template Specialization When Using Different Objects

multiple definition of template specialization when using different objects

Intuitively, when you fully specialize something, it doesn't depend on a template parameter any more -- so unless you make the specialization inline, you need to put it in a .cpp file instead of a .h or you end up violating the one definition rule as David says. Note that when you partially specialize templates, the partial specializations do still depend on one or more template parameters, so they still go in a .h file.

Why the linker complains about multiple definitions in this template?

Its because complete explicit template specializations must be defined only once - While the linker allows implicit specializations to be defined more than once, it will not allow explicit specializations, it just treats them as a normal function.

To fix this error, put all specializations in source file like:

// header

// must be in header file because the compiler needs to specialize it in
// different translation units
template<typename T>
T maximum(const T & a, const T & b)
{
return a > b ? a : b ;
}

// must be in header file to make sure the compiler doesn't make an implicit
// specialization
template<> int maximum(const int & a, const int & b);

// source

// must be in source file so the linker won't see it twice
template<>
int maximum(const int & a, const int & b)
{
return a > b ? a : b ;
}

How linker allow multiple definitions of a function template in different object files but only allow one-definition of ordinary functions

However, I start to be curious why nm gives different marks on Cygwin than on Ubuntu?? and Why linker on Cgywin can handle two T definitions correctly?

You need to understand that the nm output does not give you the full picture.

nm is part of binutils, and uses libbfd. The way this works is that various object file formats are parsed into libbfd-internal representation, and then tools like nm print that internal representation in human-readable format.

Some things get "lost in translation". This is the reason you should ~never use e.g. objdump to look at ELF files (at least not at the symbol table of the ELF files).

As you correctly deduced, the reason multiple max<int>() symbols are allowed on Linux is that the compiler emits them as a W (weakly defined) symbol.

The same is true for Windows, except Windows uses older COFF format, which doesn't have weak symbols. Instead, the symbol is emitted into a special .linkonce.$name section, and the linker knows that it can select any such section into the link, but should only do that once (i.e. it knows to discard all other duplicates of that section in any other object file).

C++ specialized method templates produce multiple definition errors

If you define specializations of a member function of a template outside the class in a header file, you need to make the specializations inline like this:

template <> 
inline bool Object::Set<double>(std::string key, double value){
}

template <>
inline bool Object::Set<float>(std::string key, float value){
}

template <>
inline bool Object::Set<std::string>(std::string key, std::string value){
}

C++ error: multiple definition of a member function specialized in template class, but I really defined it only once

An explicit function template specialization (having no template parameters) is not implicitly inline like actual templates are.

Either move the definitions to a *.cpp file, or mark them inline.

If you move them to a *.cpp file, you should declare them in the header file, like

template <>
const Vector _Grid<float>::grad(const Vector& x) const;

Template specialization issue

Specialized templated function is not template anymore, it should be treated as normal global function. So, place it to .cpp file, or declare as static or inline.

– answer by Alex F

How to access template specialization objects through variables

Obvious Answer: No, template parameters are evaluated at compile-time. They cannot hold runtime values inside them (In your case, i is a runtime variable). As such, there is no straightforward way to tackle your problem.

Alternative: Well, technically, in your case, the closest you could do to achieve something like this is to wrap the tedious part inside a macro for convenience:

// ...
for (const auto &i : v)
{
/* This macro wraps around the checking of i's value and also assigns an alias for Map that
can be used repeatedly */
#define ITER_VERTEX_TYPE(x, body) if (i == VertexType::x) { \
using Map = Map<VertexType::x>; \
body; \
}

// Now you can use it like this:
ITER_VERTEX_TYPE(Position2D, {
// 'Map' is a type alias defined by the macro that refers to 'Map<VertexType::Position2D>'
des.push_back(D3D11_INPUT_ELEMENT_DESC{ Map::semantic, 0, Map::dxgiFormat, 0, offset,
D3D11_INPUT_PER_VERTEX_DATA, 0 });
offset += Map::offset;
})

// Now do the same for the other enum values of 'VertexType' ...

// Remove the macro since we don't need it anymore
#undef ITER_VERTEX_TYPE
}
// ...


Related Topics



Leave a reply



Submit