0

I'm getting linker errors from clang++ when trying to use a templated operator I wrote.

The errors are:

main.cpp:(.text+0xfe): undefined reference to `operator<<(std::ostream&, schematic<130ul, 128ul, 130ul> const&)'
main.cpp:(.text+0x28c): undefined reference to `operator<<(std::ostream&, schematic<130ul, 1ul, 130ul> const&)'

Now before I continue or you flag this as duplicate: I know you can't put a template definition in a separate .cpp file, and I didn't do that. The operator's definition is in a separate header file that gets included into the one with it's declaration, as described in this answer. Since it's still giving me linker errors, I'm asking here.

Code

main.cpp

// includes

int main(int argc, char const* argv[])
{
    // ...

    switch (/* call */)
    {
        case /* one */:
            fout << mapArtFlat(/* ctor params */).exportScematic();
        break;
        case /* another */:
            fout << mapArtStaircase(/* ctor params */).exportSchematic();
        break;
    }
    return 0;
}

schematic.h

#ifndef SCHEMATIC_H
#define SCHEMATIC_H

// includes

template <std::size_t W, std::size_t H, std::size_t L>
class schematic
{
    friend std::ostream& operator<<(std::ostream&, const schematic<W,H,L>&);

    // class things
};

// output operator
template <std::size_t W, std::size_t H, std::size_t L>
std::ostream& operator<<(std::ostream&, const schematic<W,H,L>&);

// ...

#include "schematic_cpp.h"
#endif

schematic_cpp.h

// ...

// output operator
template <std::size_t W, std::size_t H, std::size_t L>
std::ostream& operator<<(std::ostream& lhs, const schematic<W,H,L>& rhs)
{
    // lot of code involving external libraries and processing data from the object
}

// ...

Things I tried

  • Commenting out the operator<< declaration in schematic.h
  • Making the operator<< inline
dan9er
  • 369
  • 2
  • 17

1 Answers1

1

Your example mostly work, can't reproduce the error you have. Still found something that should be changed.

First, you can't declare a friendship on a function that isn't declared yet. You need to put the template operator<< declaration before the class definition. However when you try to do so you realize you need the schematic class to be declared since its part of the type of the function. Forward declare that class and you should be ok:

template <std::size_t W, std::size_t H, std::size_t L>
class schematic;

template <std::size_t W, std::size_t H, std::size_t L>
std::ostream& operator<<(std::ostream&, const schematic<W,H,L>&);

template <std::size_t W, std::size_t H, std::size_t L>
class schematic {
    // ... stuff ...
};

Secondly, you need to explicitly state the template argument for function you are declaring as friend (or declare that you are friend with every function with every template parameter). You can do so like this:

template <std::size_t W, std::size_t H, std::size_t L>
class schematic
{
    friend std::ostream& operator<<<W,H,L>(std::ostream&, const schematic<W,H,L>&);
    // ... class stuff ...
};

If fixing these doesn't solve your problem try to post a complete minimal reproducible example of the issue you have. Your linking problem may be related to the template instantiation being discarded because of something you did in your implementation.

pqnet
  • 6,070
  • 1
  • 30
  • 51