-2

I'm trying to overload a function while adhering to the DRY principle. The only difference between overloads are argument types, so I chose to use templating. I came up with essentially the following code:

a.h:

#ifndef A_H
#define A_H
    
#include <vector>
    
template<typename T>
void func(std::vector<T>& vec);
    
void func(std::vector<double>& vec) { func<double>(vec); }
    
void func(std::vector<int>& vec) { func<int>(vec); }
    
void otherfunc();
    
#endif // A_H

a.cc:

#include "a.h"
    
template<typename T>
void func(std::vector<T>& vec)
{
  vec.resize(10);
}
    
void otherfunc()
{
  std::vector<double> x;
  func(x);
}
    
template void func<double>(std::vector<double>&);
template void func<int>(std::vector<int>&);

main.cc:

#include "a.h"
    
int main()
{
  otherfunc();
  return 0;
}

This code produces a linking error:

/nix/store/y5jcw4ymq7qi735wbm7va9yw3nj2qpb9-binutils-2.39/bin/ld: /run/user/1000/cc6xxYLN.o: in function `func(std::vector<double, std::allocator<double> >&)':
main.cc:(.text+0x0): multiple definition of `func(std::vector<double, std::allocator<double> >&)'; /run/user/1000/ccUyR0Cy.o:a.cc:(.text+0x0): first defined here
/nix/store/y5jcw4ymq7qi735wbm7va9yw3nj2qpb9-binutils-2.39/bin/ld: /run/user/1000/cc6xxYLN.o: in function `func(std::vector<int, std::allocator<int> >&)':
main.cc:(.text+0x10): multiple definition of `func(std::vector<int, std::allocator<int> >&)'; /run/user/1000/ccUyR0Cy.o:a.cc:(.text+0x80): first defined here
collect2: error: ld returned 1 exit status

Surprisingly, when not using explicit instantiation, weird link errors occur:

/nix/store/y5jcw4ymq7qi735wbm7va9yw3nj2qpb9-binutils-2.39/bin/ld: /run/user/1000/ccpXFxFV.o: in function `func(std::vector<double, std::allocator<double> >&)':
main.cc:(.text+0x0): multiple definition of `func(std::vector<double, std::allocator<double> >&)'; /run/user/1000/ccMYxyNR.o:a.cc:(.text+0x0): first defined here
/nix/store/y5jcw4ymq7qi735wbm7va9yw3nj2qpb9-binutils-2.39/bin/ld: /run/user/1000/ccpXFxFV.o: in function `func(std::vector<int, std::allocator<int> >&)':
main.cc:(.text+0x10): multiple definition of `func(std::vector<int, std::allocator<int> >&)'; /run/user/1000/ccMYxyNR.o:a.cc:(.text+0xc0): first defined here
/nix/store/y5jcw4ymq7qi735wbm7va9yw3nj2qpb9-binutils-2.39/bin/ld: /run/user/1000/ccpXFxFV.o: in function `func(std::vector<double, std::allocator<double> >&)':
main.cc:(.text+0x1): undefined reference to `void func<double>(std::vector<double, std::allocator<double> >&)'
/nix/store/y5jcw4ymq7qi735wbm7va9yw3nj2qpb9-binutils-2.39/bin/ld: /run/user/1000/ccpXFxFV.o: in function `func(std::vector<int, std::allocator<int> >&)':
main.cc:(.text+0x11): undefined reference to `void func<int>(std::vector<int, std::allocator<int> >&)'
collect2: error: ld returned 1 exit status

Why do these errors occur? How the code can be fixed?

I'm using GCC 11.3.0 with -Wall -Wextra -std=c++17 flags.

lu4nik
  • 17
  • 5
  • Try using `::func(vec);` instead of `func(vec);` – NathanOliver Apr 10 '23 at 15:17
  • 3
    Typo? `template void func(std::vector&);` Do you want `func` to expect a `std::vector`? – Drew Dormann Apr 10 '23 at 15:17
  • @DrewDormann That's correct, I totally missed it while writing and checking the code, will update the question. – lu4nik Apr 10 '23 at 15:25
  • @NathanOliver it still produces the same error. Could you explain how `::` can help here? I thought that the function declarations are already in the top-level namespace. – lu4nik Apr 10 '23 at 15:33
  • 2
    In `a.h`, you have two function declaration-definitions, but they are not marked `inline`. Is that an oversight? – Eljay Apr 10 '23 at 15:33
  • @Eljay You're right! Totally missed ODR violation for those functions! – lu4nik Apr 10 '23 at 15:40

1 Answers1

0

I missed the inline specifier for void func(std::vector<double>&) and void func(std::vector<int>&) functions, as their definitions are in a header file. Thanks to @DrewDormann and @Eljay!

lu4nik
  • 17
  • 5