0

For various reasons, I want to make a functor that is a static member of another class. However, this SOMETIMES causes a linker error. Is this not legal? If so, why not?

Here's a minimal example.

#include <iostream>

struct {
  int operator() (int x) {return x*x;} 
} standaloneFunctor;

struct Thing {
  struct {           int operator() (int x) {return x*x;}   } memberFunctor;
  static struct {    int operator() (int x) {return x*x;}   } staticFunctor;
};

int main () {
  
  std::cout << standaloneFunctor(3) << '\n';   // call the stand-alone functor
  
  Thing thing;
  std::cout << thing.memberFunctor(3) << '\n';  // call functor that is member of class
  
  std::cout << Thing::staticFunctor(3) << '\n'; // call functor that is static member of class
  return 0;
}

Compiling and linking with -O0 causes a linker error:

yloh$ g++ a.cc -O0 -o a ; ./a
/usr/bin/ld: /tmp/ccd6rdI7.o: in function `main':
a.cc:(.text+0x8e): undefined reference to `Thing::staticFunctor'
collect2: error: ld returned 1 exit status
bash: ./a: No such file or directory

Compiling and linking with -O3 leads to the expected result in this case (but fails for more sophisticated programs):

yloh$ g++ a.cc -O3 -o a ; ./a
9
9
9

The compiler version is g++ (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0. Can anyone explain what causes the linker error, and suggest a workaround? [Presumably one workaround is to define a dummy object and call the functor that is its data member, but that sounds hacky.] Thanks in advance!

  • you need to define the static member – 463035818_is_not_an_ai Feb 22 '23 at 15:31
  • Just a guess: -O0 expects a static member to be defined in a compilation unit (not just declared). -O3 will switch on inline function optimization, which does not require a separate compilation unit for the function any more. – Doc Brown Feb 22 '23 at 15:36
  • Refer to [how to ask](https://stackoverflow.com/help/how-to-ask) where the first step is to *search and then research* and you'll find plenty of related SO posts. – Jason Feb 22 '23 at 15:37
  • Note that both `memberFunctor` and `staticFunctor` have only been declared. A static member also needs a definition, so the "workaround" is to be a good programmer and add one. This is a bit convoluted since the type has no name, but `decltype(Thing::staticFunctor) Thing::staticFunctor;` should do the trick. – molbdnilo Feb 22 '23 at 15:46
  • Thanks all! molbdnilo, decltype(Thing::staticFunctor) Thing::staticFunctor worked. I should have known -- I did encounter this issue before. I kept thinking it was something to do with functors. Since the issue wasn't functor-related at all, feel free to mark as duplicate. – Yen Lee Loh Feb 22 '23 at 15:55

0 Answers0