我有以下头文件/源文件:
// foo.h
#ifndef __FOO_H
#define __FOO_H
#include <map>
#include <stdexcept>
template <typename T>
class FooBase {
public:
std::map<float,T> a;
FooBase(std::map<float,T> a_) : a(a_) {};
T func(float x1, T fallback) const;
virtual T func(float x1) const = 0;
};
class Foo: public FooBase<float> {
public:
Foo() : FooBase<float>({}) {};
float func(float x1) const;
// float func(float x1, float fallback) const;
};
void test_foo1();
void test_foo2();
#endif // __FOO_H
// foo.cpp
#include "foo.h"
template <typename T>
T FooBase<T>::func(float x1, T fallback) const {
try {
return (func(x1));
} catch(std::runtime_error&) {
return fallback;
}
};
float Foo::func(float x1) const {
return 2.0;
};
template class FooBase<float>;
void test_foo1() {
Foo foo;
float b = foo.func(1.0, 2.0);
}
void test_foo2() {
Foo foo;
float b = foo.func(1.0);
}
至关重要的是;回退"-func
的版本与虚拟函数的名称相同,但签名不同,而func
的单签名版本将在子类Foo
中指定。
test_foo1
-函数无法编译:
[ 3%] Building CXX object foo.cpp.o
foo.cpp: In function ‘void test_foo1()’:
foo.cpp:20:29: error: no matching function for call to ‘Foo::func(double, double)’
20 | float b = foo.func(1.0, 2.0);
| ^
foo.cpp:12:7: note: candidate: ‘virtual float Foo::func(float) const’
12 | float Foo::func(float x1) const {
| ^~~
foo.cpp:12:7: note: candidate expects 1 argument, 2 provided
如果我在foo.h
中激活注释声明行,它会编译,但在另一个源文件中调用test_foo1
时无法解析。在这种情况下,我使用了catch2
-测试,当包含test_foo1
时,该测试失败,而test_foo2
没有问题:
[ 98%] Linking CXX executable ...
/usr/bin/ld: libFoo.so: undefined reference to `Foo::func(float, float) const'
有人能告诉我,如果我在如何实现这一点上完全错了吗?我不愿意分享构建的全部逻辑,因为重复的声明可能无论如何都是错误的方法。我希望test_foo2
在另一个源文件中工作这一事实能够产生足够的信任,从而排除位于共享代码之外的问题。
基本思想是在GOF语言中;模板方法模式";带有一个没有默认值的钩子函数。特别的是,hook方法与调用它的函数同名。类具有state(a
(和模板参数这一事实可能会产生影响,至少我认为我在更简单的情况下实现了这样的功能,因此我将state和模板参数包含在";最小示例";,希望这不会让事情变得太复杂。
谢谢你的帮助。
Foo::func
隐藏FooBase::func
。您可以使用using
将FooBase::func
拉入Foo
的作用域:
class Foo: public FooBase<float> {
public:
Foo() : FooBase<float>({}) {};
float func(float x1) const;
using FooBase<float>::func;
};
实时演示
或者,您可以明确选择要调用的FooBase::func
:
void test_foo1() {
Foo foo;
float b = foo.FooBase<float>::func(1.0, 2.0);
}