0

Having recently discovered templates, I've been trying to get a good grasp on them and came across a usage for them that I'd really like to implement; but having tried multiple things, I keep getting errors.

I'm trying to create a function that can take multiple types of parameters at once in any order.

(I'm using VS 2013.)

What I have right now is an "already defined" error (only when including tem.h in more than one file):

the exact first error (the rest are basically the same just for each test.. overload?):

Error 1 error LNK2005: "void __cdecl test<struct A>(struct A *)" (??$test@UA@@$$$V@@YAXPAUA@@@Z) already defined in main.obj c:\Users\User\documents\visual studio 2013\Projects\TemplateTest\TemplateTest\foo.obj TemplateTest

foo is just a .cpp file containing only: #include "tem.h"

tem.h:

#ifndef TEM_H
#define TEM_H

struct A {};

struct B {};

#include <iostream>

template<typename First, typename... Rest>
void test(First *t, Rest&&... args){
    test(t);
    test(std::forward<Rest>(args)...);
}

template<>
void test<A>(A *val){
    std::cout << "Handled A" << std::endl;
}
template<>
void test<B>(B *val){
    std::cout << "Handled B" << std::endl;
}

#endif

main.cpp:

#include <iostream>
#include "tem.h"

int main(int argc, char *argv[]){
    std::cout << "running test..." << std::endl;
    A a;
    B b;
    test(&a, &b);
    return 0;
}

What am I missing that is causing this error?

Edit: Making each instance of test inline prevents the error, but I don't think that's really the best solution

G. Chi
  • 49
  • 6
  • What exactly is already defined? Always show full unedited error messages. – n. m. could be an AI Oct 23 '14 at 08:31
  • @n.m. `Error 1 error LNK2005: "void __cdecl test(struct A *)" (??$test@UA@@$$$V@@YAXPAUA@@@Z) already defined in main.obj c:\Users\User\documents\visual studio 2013\Projects\TemplateTest\TemplateTest\foo.obj TemplateTest ` and a few more like it. foo is just a c++ source file with `#include "tem.h"` at the top – G. Chi Oct 23 '14 at 09:09
  • 1
    There are a 4,206,904 duplicates of this question on StackOverflow – Jonathan Wakely Oct 23 '14 at 09:23
  • @JonathanWakely and originally it was formatted to address that and how even trying the solutions found I was still getting errors, but it was marked as a duplicate of a question of whose solution was already tried, with errors – G. Chi Oct 23 '14 at 09:35
  • Looking at your original question, the problem was with the primary template (the variadic one) which was not defined in the header and not instantiated in `tem.cpp`, so you got a missing definition error. Your attempt to fix it reversed the situation, by defining _everything_ in the header, which gives multiple definition errors. The solution is to define everything inline (and put `inline` on the specializations!) or put the primary (i.e. unspecialized) function template in the header, and the specializations in the .cpp file. – Jonathan Wakely Oct 23 '14 at 10:52
  • And there are still hundreds of duplicate questions, you just didn't understand the answers and how to fix your code. – Jonathan Wakely Oct 23 '14 at 10:53

1 Answers1

3

Function template specializations are not themselves templates, they are normal functions with fancy syntax. Like any other normal function, they should not be defined in header files unless you use the inline keyword.

Either add inline to both specializations, or leave just their declarations in the header and move the definitions to some .cpp file.

The main template definition is OK and should be left in the header intact.

A general advice though is to avoid function template specializations. You can use normal non-template overloads:

void test (A*);
void test (B*);
n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • That's what I tried secondly. It was giving me an "unresolved external symbol" error, and when I posted it as a question it was marked as a duplicate of this: http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file?lq=1 – G. Chi Oct 23 '14 at 09:28
  • +1 @G.Chi you should have no issues by simply `inline void test(A* a) {...}` if you really want those functions (which I concur, should be overloads, not specialized) in the header file. – WhozCraig Oct 23 '14 at 09:31
  • What I was trying to achieve is a function that I can pass multiple objects to of different types and they'd be handled according to their type. As far as I'm aware I can't achieve that with just overloads – G. Chi Oct 23 '14 at 09:33
  • 3
    @G.Chi And again, no one ever said you can't use templates. The variadic template can stay. The two specializations you're attempting *don't have to be specialized.* They can simply be inline overloads. – WhozCraig Oct 23 '14 at 09:34
  • 2
    You probably have tried to implement both the main template and the specialisations in a .cpp file, which would be wrong. – n. m. could be an AI Oct 23 '14 at 09:35
  • Well I'll be darned. I could have sworn I tried that in my actual usage case and was still getting errors, but that solves it too without any need for making it inline. thanks! Also I now see what you and @WhozCraig are talking about and you're right, using only the main template and just overloads for the individual type cases is much better – G. Chi Oct 23 '14 at 09:45