22

When I pass a template function as a template parameter of a base class, the linker complains that it cannot link the function:

#include <stdio.h> template<int I> inline int identity() {return I;} //template<> inline int identity<10>() {return 20;} template<int (*fn)()> class Base { public: int f() { return fn(); } }; template<int Val> class Derived : public Base<identity<10> > { public: int f2() { return f(); } }; int main(int argc, char **argv) { Derived<10> o; printf("result: %d\n", o.f2()); return 0; } 

Results in:

$ g++ -o test2 test2.cpp && ./test2 /tmp/ccahIuzY.o: In function `Base<&(int identity<10>())>::f()': test2.cpp:(.text._ZN4BaseIXadL_Z8identityILi10EEivEEE1fEv[_ZN4BaseIXadL_Z8identityILi10EEivEEE1fEv]+0xd): undefined reference to `int identity<10>()' collect2: error: ld returned 1 exit status 

If I comment out the specialization, then the code compiles and links as expected. Also, if I inherit from Base<identity<Val> > instead of Base<identity<10> >, the code works as I expect.

Try here: http://coliru.stacked-crooked.com/a/9fd1c3aae847aaf7

What do I miss?

4
  • 3
    This problem seems to be a gcc bug: it compiles and links OK using clang and icc. BTW, the name identity() is normally used for transformation where the result is identical to the argument. Commented Dec 30, 2016 at 16:04
  • @DietmarKühl Well, identity<X>() returns X. :-) Commented Dec 30, 2016 at 16:05
  • 2
    The workaround: class Derived : public Base<static_cast<int(*)()>(identity<10>) >. live demo Commented Dec 30, 2016 at 16:07
  • @melpomene: sure. However, the template parameter seems to be more something like an index (as in f<sub>i</sub>()) than a function argument. Commented Dec 30, 2016 at 16:07

2 Answers 2

19

It seems the problem is a gcc error: the code compiles and links with clang, icc, and the EDG frontend. A potential work-around not changing any of the uses would be the use of a class template identity instead of a function:

template<int I> struct identity { operator int() { return I; } }; template<typename fn> class Base { public: int f() { return fn(); } }; 
Sign up to request clarification or add additional context in comments.

1 Comment

Not making the function template inline could also work. Isn't linker supposed to remove duplicate template instantiations anyway?
9

Lifting it out into a typedef makes it compile, i.e.

typedef Base< identity<10> > base10; 

I am not quite sure why doing it straight in the class definition doesn't work.

http://coliru.stacked-crooked.com/a/f00b4f4d1c43c2b0

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.