1

I'm trying to get plain function pointer from some std::function. The task has been discussed number of times at SO (like here) and was admitted unsolvable. But I tried such a solution (I fixed the function pointer signture and degenerated the usage of a plain function pointer for the sake of simplicity):

#include <functional>

typedef int(*fp)(int);

template<int idx, typename F>
struct wrap_f_struct {
    static F impl;

    static int f(int a) { return impl(a); }    
};

template<int idx, typename F>
fp wrap_f(F f) { 
    wrap_f_struct<idx, F>::impl = f;
    return wrap_f_struct<idx, F>::f;
}

int add(int a, int b) { return a + b; }

int main() {
    using namespace std::placeholders; 
    std::function<int(int)> add2 = std::bind(add, _1, 2);

    (wrap_f<1>(add2))(1);
}

Well, this isn't linking for some reason I can't understand:

/tmp/ccrcFz32.o: In function `int (*wrap_f<1, std::function<int (int)> >(std::function<int (int)>))(int)':
cast_fp_min.cpp:(.text._Z6wrap_fILi1ESt8functionIFiiEEEPS1_T0_[_Z6wrap_fILi1ESt8functionIFiiEEEPS1_T0_]+0x10): undefined reference to `wrap_f_struct<1, std::function<int (int)> >::impl'
/tmp/ccrcFz32.o: In function `wrap_f_struct<1, std::function<int (int)> >::f(int)':
cast_fp_min.cpp:(.text._ZN13wrap_f_structILi1ESt8functionIFiiEEE1fEi[_ZN13wrap_f_structILi1ESt8functionIFiiEEE1fEi]+0x10): undefined reference to `wrap_f_struct<1, std::function<int (int)> >::impl'
collect2: error: ld returned 1 exit status

My question is: can someone explain me the exact reason why this linkage error occurs?

Community
  • 1
  • 1
Artem Pelenitsyn
  • 2,508
  • 22
  • 38
  • 2
    This question has nothing to do with functions or pointers or templates. It's just the tired old "define your static class members" problem from C++101. – Kerrek SB Oct 13 '13 at 17:42
  • 1
    Your "solution" is also massively non-reentrant. It's basically impossible to *store* the result of `wrap_f` in a meaningful way. – Kerrek SB Oct 13 '13 at 17:43
  • @KerrekSB if you use different integer constants when instantiating wrap_t (1 in example), you can store return values safely, afaics. – Artem Pelenitsyn Oct 13 '13 at 18:05
  • It's technically safe, but multi-threaded programs tend to be big. This type of solution scales poorly, and makes programs very hard to debug. – MSalters Oct 13 '13 at 23:12
  • @MSalters can't see, what problems could arise in MT programs due to this solution (except those, which could arise in any MT programs and don't depend on this particular approach), would you please expand on this? – Artem Pelenitsyn Oct 14 '13 at 05:15

1 Answers1

1

Static member variables are only declared in a structure/class. They need to be defined as well, which you do not do.

Add e.g.

template<int idx, typename F>
F wrap_f_struct<idx, F>::impl;
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621