1

Why am I getting link errors on this program (with gcc 4.6.2):

#include <iostream>

// prints something; 
// the template doesn't add anything
template <typename T>
struct Printer
{
    void print()
    {
        std::cout << "Printer::print" << std::endl;
    }
};

// this is an actual template
// calls the method indicated by the second template argument
// belonging to the class indicated by the first template argument
template < typename U, void(U::*func)()>
struct Caller
{
    void call(U obj)
    {
        (obj.*func)();
    }
};

// just a wrapper
template<typename V>
struct Wrapper
{
    void call_caller_on_printer()
    {
        Printer<int> a_printer;
        Caller<Printer<int>, &Printer<int>::print> caller;
        caller.call(a_printer);
    }
};

int main()
{
    Wrapper<int> the_wrapper;
    the_wrapper.call_caller_on_printer();

    return 0;
}

The linker complains that Printer::print is an undefined reference. However, if you make Wrapper a non-template (the template doesn't add anything there), it works. The print method of Printer does not seem to be instantiated. Why is that?

ildjarn
  • 62,044
  • 9
  • 127
  • 211
Rekr
  • 35
  • 3
  • 2
    FWIW, works on [GCC 4.3.4](http://ideone.com/pR7y6) and MSVC10, fails on [GCC 4.5.1](http://ideone.com/6VDTp). Looks like a regression to me. – ildjarn Feb 15 '12 at 23:20

1 Answers1

0

I’ve had a problem that looks similar on GCC 4.5.1 (and yes, it does look like a regression).

In my case, it helped to explicitly cast the pointer to the desired type to make GCC 4.5.1 swallow this code. Try doing the same here. I.e.

Caller<Printer<int>, static_cast<void (Printer<int>::*)()>(&Printer<int>::print)> caller;

(Untested; incidentally, is a cast even syntactically valid here? Otherwise a metafunction might help.)

Community
  • 1
  • 1
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • Unfortunately, the suggestion doesn't compile (the `static_cast` passed as a template argument is the problem). However, the general idea (manipulating the offending `Printer::print` somehow) is useful as it may force the compiler to instantiate it for other reasons. Taking its address does the trick: `void(Printer::*x)() = &Printer::print`; – Rekr Feb 16 '12 at 14:58