【发布时间】:2017-11-15 08:11:02
【问题描述】:
这是我的代码,在这里你可以看到带有接口函数Do() 的Base 类型的对象,我总是使用Base 类型的对象(模板具有更多类型)并且总是调用Do() 接口。因此,对于ImplBaseDummy1 和ImplBaseDummy2,我可以得到f() 的ImplBaseDummy2 的具体实现或Base 的默认实现ImplBaseDummy1。到目前为止,这一切都很好,我有很多代码可以按预期工作,我不想更改 API,但如果你能说服我应该这样做,我可能会这样做。最近我不得不添加更多类型,比如ImplBase 我尽量不要重复代码,所以我创建了一个类似的结构,希望它能够继续工作。问题是如何在定义时强制调用f 的特定实现,并在缺少特定实现时使用默认实现(来自Base),所有这些都应该在为@987654336 类型的对象调用接口函数Do() 时发生@(以某种方式模板化)。
#include <iostream>
template <class Impl>
class Base
{
public:
void Do() { f_impl(); }
void f() {std::cout << "Base::f" << std::endl; }
protected:
void f_impl() { static_cast<Impl*>(this)->f(); }
};
class ImplBaseDummy1 : public Base<ImplBaseDummy1>
{
};
class ImplBaseDummy2 : public Base<ImplBaseDummy2>
{
public:
void f() {std::cout << "ImplBaseDummy2::f" << std::endl; }
};
template <class Actual>
class ImplBase : public Base<ImplBase<Actual>>
{
public:
typedef Base<ImplBase<Actual>> Parent;
void f() { static_cast<Actual*>(this)->f(); }
};
class Derived1 : public ImplBase<Derived1>
{
public:
typedef ImplBase<Derived1> Parent;
void f() {std::cout << "Derived1::f" << std::endl; }
};
class Derived2 : public ImplBase<Derived2>
{
public:
typedef ImplBase<Derived2> Parent;
using Parent::Parent::f;
};
int main()
{
Base<ImplBaseDummy1> d01;
d01.Do();
Base<ImplBaseDummy2> d02;
d02.Do();
Base<ImplBase<Derived1>> d1;
d1.Do();
Base<ImplBase<Derived2>> d2;
d2.Do();
return 0;
}
此代码按预期编译和运行。我的问题是关于我想实现的安全机制,以防我忘记在Derived2 中写using Parent::Parent::f;(这是最初的意图,如果缺少特定实现,请从Base 调用默认实现)。在这种情况下,ImplBase<Derived2>::f() 会无限期地调用自身,直到它崩溃(或者在编译 -O3 优化级别时永远不会退出)。我想实现它类似于这个
void f() { static_assert(&f != &Actual::f, "function calls itself"); static_cast<Actual*>(this)->f(); }
void f() { static_assert(!std::is_same<decltype(f), decltype(Actual::f)>::value, "function calls itself"); static_cast<Actual*>(this)->f(); }
但是两个实现都没有编译,还有其他想法如何实现这个检查吗?需要强调的是,运行时解决方案不是我要寻找的,我最好不要进行任何检查,并且在遇到问题时打破我的头,而不是对Do 接口的任何调用执行额外的测试。
【问题讨论】:
-
您可以使用PRETTY_FUNCTION 查看调用了哪个函数以及何时调用
-
在所有情况下,您都无法检测到间接递归(例如,您的函数调用
foo,而bar又调用您的函数)。 -
@Bl4ckb0ne,如果我可以在编译时比较来自 ImplBase::f 的 PRETTY_FUNCTION 和 Actual::f 的 PRETTY_FUNCTION,那就太好了,但我认为这做不到。
-
@BasileStarynkevitch,我想谈谈非常具体的情况,而不是一般情况
-
您愿意花几个月的时间来编写您的验证程序?