C++:未定义对仿函数重载调用运算符的引用
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;
}
编译上述代码时,g++ 将其打印到控制台:
/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
我不太明白 HowMuch
中的 Prediate<V>
定义有什么问题,因为对我(C++ 的新手)来说,它看起来真的很 LGTM。根据我的理解,编译器将 Predicate<int>
的定义创建为一个单独的类型,日志也正是这样说的,但由于某种原因,它找不到重载调用运算符的类型化定义。可能是类型推导的问题?容器模板类型本身的模板必须以某种方式明确定义?
编辑:
virtual
修饰符被添加到 Predicate
和 Producer
的函数运算符重载中,但问题似乎仍然存在。错误"description"(如果它可以被称为有用的描述)有点改变,但是(但它仍然指向相同的问题):
/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
您需要为 类 的所有功能提供定义。这意味着即使您仅从 Predicate
和 Producer
派生 类,您仍然必须在 类.
中实现 operator()
如果您不想这样做(即只有函数声明但没有定义),请考虑通过声明 类 abstract =12=] 方法 纯虚拟 。那么你不能直接从这些 类 实例化一个对象,而只能从实现 operator()
方法的 derived 类 实例化一个对象。这也意味着您只能在 HowMuch
构造函数中传递 Predicate<V>*
。
如果你想让 Predicate 成为一个抽象的class,你需要:
-使 bool operator() 方法成为虚拟方法并将其设置为 0(在 Predicate class 中):
virtual bool operator()(const T& x) const=0;
-在 HowMuch 中存储对谓词的引用:
explicit HowMuch(Predicate<V> &p) : predicate{p} {}
Predicate<V> &predicate;
在你的情况下继承似乎不合理,你可能会摆脱你的基础 classes:
template <typename T>
class LessThan {
public:
explicit LessThan(const T& v) : val(v) {}
bool operator()(const T& x) const { return x < val; }
private:
T val;
};
template <typename Predicate>
class HowMuch {
public:
explicit HowMuch(Predicate p) : predicate{p} {}
template <typename Container>
int operator()(const Container& c) const {
int count = 0;
for (const auto& x : c)
if (predicate(x)) ++count;
return count;
}
private:
Predicate predicate;
};
int main() {
const LessThan<int> lf(5);
const HowMuch<LessThan<int>> hm(lf);
std::list<int> li {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::cout << "How much numbers less than 5 is in {1, 2, 3, 4, 5, 6, 7, 8, 9, "
"10}? Answer: "
<< hm(li)
<< std::endl;
}
如果你真的想要基class作为接口,你需要纯虚调用
template <typename T>
class Predicate {
public:
virtual ~Predicate() = default;
virtual bool operator()(const T& x) const = 0;
};
template <typename C, typename T>
class Producer {
public:
virtual ~Producer() = default;
virtual T operator()(const C& c) const = 0;
};
您还需要修复您拥有的对象切片:
template <typename C, typename V>
class HowMuch : public Producer<C, int> {
public:
explicit HowMuch(const Predicate<V>& p) : predicate{&p} {}
int operator()(const C& c) const override {
int count = 0;
for (const auto& x : c)
if ((*predicate)(x)) ++count;
return count;
}
private:
const Predicate<V>* predicate;
};
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;
}
编译上述代码时,g++ 将其打印到控制台:
/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 toPredicate<int>::operator()(int const&) const
collect2: error: ld returned 1 exit status The terminal process terminated with exit code: 1
我不太明白 HowMuch
中的 Prediate<V>
定义有什么问题,因为对我(C++ 的新手)来说,它看起来真的很 LGTM。根据我的理解,编译器将 Predicate<int>
的定义创建为一个单独的类型,日志也正是这样说的,但由于某种原因,它找不到重载调用运算符的类型化定义。可能是类型推导的问题?容器模板类型本身的模板必须以某种方式明确定义?
编辑:
virtual
修饰符被添加到 Predicate
和 Producer
的函数运算符重载中,但问题似乎仍然存在。错误"description"(如果它可以被称为有用的描述)有点改变,但是(但它仍然指向相同的问题):
/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
您需要为 类 的所有功能提供定义。这意味着即使您仅从 Predicate
和 Producer
派生 类,您仍然必须在 类.
operator()
如果您不想这样做(即只有函数声明但没有定义),请考虑通过声明 类 abstract =12=] 方法 纯虚拟 。那么你不能直接从这些 类 实例化一个对象,而只能从实现 operator()
方法的 derived 类 实例化一个对象。这也意味着您只能在 HowMuch
构造函数中传递 Predicate<V>*
。
如果你想让 Predicate 成为一个抽象的class,你需要:
-使 bool operator() 方法成为虚拟方法并将其设置为 0(在 Predicate class 中):
virtual bool operator()(const T& x) const=0;
-在 HowMuch 中存储对谓词的引用:
explicit HowMuch(Predicate<V> &p) : predicate{p} {}
Predicate<V> &predicate;
在你的情况下继承似乎不合理,你可能会摆脱你的基础 classes:
template <typename T>
class LessThan {
public:
explicit LessThan(const T& v) : val(v) {}
bool operator()(const T& x) const { return x < val; }
private:
T val;
};
template <typename Predicate>
class HowMuch {
public:
explicit HowMuch(Predicate p) : predicate{p} {}
template <typename Container>
int operator()(const Container& c) const {
int count = 0;
for (const auto& x : c)
if (predicate(x)) ++count;
return count;
}
private:
Predicate predicate;
};
int main() {
const LessThan<int> lf(5);
const HowMuch<LessThan<int>> hm(lf);
std::list<int> li {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::cout << "How much numbers less than 5 is in {1, 2, 3, 4, 5, 6, 7, 8, 9, "
"10}? Answer: "
<< hm(li)
<< std::endl;
}
如果你真的想要基class作为接口,你需要纯虚调用
template <typename T>
class Predicate {
public:
virtual ~Predicate() = default;
virtual bool operator()(const T& x) const = 0;
};
template <typename C, typename T>
class Producer {
public:
virtual ~Producer() = default;
virtual T operator()(const C& c) const = 0;
};
您还需要修复您拥有的对象切片:
template <typename C, typename V>
class HowMuch : public Producer<C, int> {
public:
explicit HowMuch(const Predicate<V>& p) : predicate{&p} {}
int operator()(const C& c) const override {
int count = 0;
for (const auto& x : c)
if ((*predicate)(x)) ++count;
return count;
}
private:
const Predicate<V>* predicate;
};