1

I have two template class, and the Leaf<T> is derived from the Base<T>, then I developed a template function which uses the reference of the Base<T> as its parameter. And set the definition and the instantiation of that function in its source file.

The issue happened once I tried to pass the Leaf<T> as the argument of that function. The compiler tries to find the symbol with Leaf<T> without the auto convention as it used to be.

// foo.h
#ifndef __FOO_H_INCLUDED__
#define __FOO_H_INCLUDED__

#include <base.h>

template <typename T>
void Foo(T &value);

#endif // __FOO_H_INCLUDED__


// foo.cpp
#include <foo.h>
#include <iostream>

template <typename T>
void Foo(T &value)
{
    std::cout<<value.getValue()<<std::endl;
}

template void Foo(MyBase<int> &value);


// main.cpp
#include <leaf.h>
#include <foo.h>

int main()
{
    int i = 20;
    MyLeaf<int> leaf;

    leaf.setValue(i);

    Foo(leaf);
}

The above snippet will throw an "undefined reference" exception in linking. Refactor the invoking as Foo<MyBase<int> >(leaf) will fix the issue but that not what I want. And explicitly instantiate all of the potential derived types is also impossible because there is no way to know how many are them.

So is there a way that could make the linker recognize my symbols with the base type rather than find the precise one and throw an error?

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
Calvin
  • 43
  • 5

1 Answers1

0

Adding an explicit template instantiation in one translation unit must be paired with an explicit template instantiation declaration to make sure the compiler doesn't try to do an implicit instantiation. Otherwise, the program is ill-formed.

Beyond that, you can't have template argument deduction deduce anything other than Foo<MyLeaf<int>> the way you have it setup. But with a bit of tweaking, we can have it working. In your header:

template <typename T>
void Foo(MyBase<T> &value);

extern template void Foo(MyBase<int> &value);

And in your implementation file:

template <typename T>
void Foo(MyBase<T> &value)
{
    std::cout<<value.getValue()<<std::endl;
}

template void Foo(MyBase<int> &value);

Now the deduction rules, and overload resolution should match the functions correctly. What we did is shift the burden. Now that function always expects a class instantiated from MyBase. And since every class instantiated from MyLeaf is also derived from one instantiated from MyBase, you see where it goes. We fulfill the templates requirement for the argument, and just leave it to deduce T from it.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • I suspect it should be the `extern template void Foo(MyLeaf &value);` here? – Calvin Jan 19 '18 at 22:43
  • @Calvin - Your example does an explicit instantiation for `MyBase`. That's where I copied it from. – StoryTeller - Unslander Monica Jan 19 '18 at 22:44
  • Unfortunately, even add both of these two explicit declarations in the `foo.h`, the error is still there. – Calvin Jan 19 '18 at 22:48
  • Thank you, but actually, I see it will work, but the solution will expand my codes a lot. My template function not only can handle the `MyBase` and its derived classes, but also other types..... – Calvin Jan 19 '18 at 22:58
  • @Calvin - What other types? Supposedly only `MyBase` has `getValue()`. If you have other bases that need support, then yes, there needs to be an overload for them as well. You can always move the implementation to a non-public template to avoid duplication. But you can't have your cake and eat it too with `Foo`. – StoryTeller - Unslander Monica Jan 19 '18 at 23:02
  • The Foo is obviously just the simplest demo for my need :) I'm working on an interface between different software and the actual Foo is like a repeater for helping user transfer data between the software. There might be thousands of ways that could work with explicitly define every potential type, then I just want to find a way that could make my codes as elegant as possible. Many thanks for your help anyway, it seems like I'll give up then do something explicitly. ;-) – Calvin Jan 19 '18 at 23:10