Liquid_Fire
Liquid_Fire

Reputation: 7048

Explicit instantiation of operator>> overload

I have a class Vector<T>, and am using a library that provides a class YAML::Node. I would like to overload operator>> for these two types.

I have added the following declaration to Vector's declaration:

friend void operator>>(YAML::Node const & node, Vector<T> & v);

I have also added the following implementation of the function:

template<typename T>
void operator>>(YAML::Node const & node, Vector<T> & v) {
    node[0] >> v.x;
    node[1] >> v.y;
    node[2] >> v.z;
}

Finally, I have added the following (attempt at) explicitly instantiating the template for T = num_t:

template
void operator>>(YAML::Node const & node, Vector<num_t> & v);

However, this results in the following linker error:

Error   9   error LNK2019: unresolved external symbol "void __cdecl operator>>(class YAML::Node const &,class Vector<double> &)" (??5@YAXAEBVNode@YAML@@AEAV?$Vector@N@@@Z) referenced in function "public: static class Scene __cdecl Scene::fromFile(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (?fromFile@Scene@@SA?AV1@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)

(num_t is a typedef for double)

However, if I add the following (non-template) implementation of the function, everything compiles fine:

void operator>>(YAML::Node const & node, Vector<num_t> & v) {
    node[0] >> v.x;
    node[1] >> v.y;
    node[2] >> v.z;
}

Why is the template version of the function not working?

Edit: Forgot to mention; the compiler is Visual Studio 11 Beta

Upvotes: 1

Views: 666

Answers (3)

Mike Seymour
Mike Seymour

Reputation: 254531

Declaring the function as a friend does not declare a function template; instead, each specialisation of the class template declares a non-template function, with its parameter types overloaded according to the template arguments. These will be chosen instead of the template you define; but they are not defined, hence the error.

To fix it, you can either declare the function template before the class template (in which case the friend declaration will make that a friend, rather than declare a new function), or define the friend function inline, inside the class template, so that each specialisation of the class template defines the function as well as declaring it.

Upvotes: 3

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 153895

Well, the problem is that the friend you declared is a non-template function which has nothing to do at all with your shift operator. In fact, your template uses any private members the compiler should complain. Here is an example how this should look like:

template <typename T>
class foo
{
public:
    template <typename S>
    friend void f(foo<S>);

private:
    T value;
};

template <typename T>
void f(foo<T> v)
{
    v.value;
}
template void f(foo<int>);

int main()
{
    foo<int> v;
    f(v);
}

If you replace the friend declaration by

friend void f(foo<T>);

This code won't link either and will actually produce a compile time error indicating that the function f() is not a friend.

Upvotes: 2

Kaz
Kaz

Reputation: 58598

That is strange. I can't see anything wrong, and even the MSDN documentation (this is Visual C++ right?) confirms that template instantiation should deduce the template arguments. The arguments in the instantiation match. Maybe it's broken for overloaded operators?

It would not hurt to try adding explicit template arguments on it.

Also, perhaps it's being confused by the typedef? You never know! Try substituting double.

Upvotes: 0

Related Questions