Search code examples
c++c++11functor

C++: undefined reference to the functor's overloaded invocation operator


template <typename T>
class Predicate {
   public:
    bool operator()(const T& x) const;
};

template <typename T>
class LessThan : public Predicate<T> {
   public:
    explicit LessThan(const T& v) : val(v) {}
    bool operator()(const T& x) const { return x < val; }

   private:
    const T val;
};

template <typename C, typename T>
class Producer {
   public:
    T operator()(const C& c) const;
};

template <typename C, typename V>
class HowMuch : public Producer<C, int> {
   public:
    explicit HowMuch(Predicate<V> p) : predicate{p} {}
    int operator()(const C& c) const {
        int count = 0;
        for (const auto& x : c)
            if (predicate(x)) ++count;
        return count;
    }

   private:
    Predicate<V> predicate;
};

int main() {
    const LessThan<int> lf(5);
    const HowMuch<list<int>, int> hm(lf);
    list<int> li {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    cout << "How much numbers less than 5 is in {1, 2, 3, 4, 5, 6, 7, 8, 9, "
            "10}? Answer: "
         << hm(li)
         << endl;
}

When compiling the aforementioned code g++ prints this to the console:

/tmp/ccblK6El.o: In function HowMuch<std::__cxx11::list<int, std::allocator<int> >, int>::operator()(std::__cxx11::list<int, std::allocator<int> > const&) const: templates.cpp:(.text._ZNK7HowMuchINSt7__cxx114listIiSaIiEEEiEclERKS3_[_ZNK7HowMuchINSt7__cxx114listIiSaIiEEEiEclERKS3_]+0x84): undefined reference to Predicate<int>::operator()(int const&) const collect2: error: ld returned 1 exit status The terminal process terminated with exit code: 1

I can't quite get what is the problem with Prediate<V> definition inside HowMuch, because for me (a newbie in C++) it really looks LGTM. From my understanding the compiler creates a definition of Predicate<int> as a separate type, and the logs say exactly that, but for some reason it can't find the typed definition of the overloaded invocation operator. May be the problem is with the type deduction? Template of a container template type itself has to be somehow explicitly defined?

EDIT:

virtual modifier was added to both Predicate's and Producer's function operator overloads, but the problem, as it seems, persists. The error "description" (if it can be called as helpful description) is changed a bit, however (but still it points to the same problem):

/tmp/ccn1Swqa.o: In function HowMuch >, int>::operator()(std::__cxx11::list > const&) const: templates.cpp:(.text._ZNK7HowMuchINSt7__cxx114listIiSaIiEEEiEclERKS3_[_ZNK7HowMuchINSt7__cxx114listIiSaIiEEEiEclERKS3_]+0x76): undefined reference to Predicate::operator()(int const&) const /tmp/ccn1Swqa.o:(.rodata._ZTV8ProducerINSt7__cxx114listIiSaIiEEEiE[_ZTV8ProducerINSt7__cxx114listIiSaIiEEEiE]+0x10): undefined reference to Producer >, int>::operator()(std::__cxx11::list > const&) const /tmp/ccn1Swqa.o:(.rodata._ZTV9PredicateIiE[_ZTV9PredicateIiE]+0x10): undefined reference to Predicate::operator()(int const&) const collect2: error: ld returned 1 exit status The terminal process terminated with exit code: 1


Solution

  • You need to provide definitions for all functions of your classes. That means even if you only derive classes from Predicate and Producer you still have to implement the operator() in those classes.

    If you don't want to do that (i.e. only have the function declaration but no definition), consider making these two classes abstract by declaring the operator() methods pure virtual. Then you cannot instantiate an object directly from these classes but only from derived classes that implement the operator() method. And that also means you can only pass Predicate<V>* in your HowMuch constructor.