這裏是我的代碼,在這裏你看到的類型爲Base
的對象具有接口函數Do()
,我總是使用類型爲Base
的對象(使用更多類型的模板)並始終調用Do()
接口。因此,對於ImplBaseDummy1
和ImplBaseDummy2
,在ImplBaseDummy1
的情況下,我得到f()
的具體實現ImplBaseDummy2
或Base
的默認實現。到目前爲止,所有這些工作都很好,我有很多代碼可以按預期工作,我不想更改API,但如果你能說服我,我可能會這樣做。最近我不得不添加更多類型,如ImplBase
我儘量不要複製代碼,所以我創建了一個類似的結構,希望它能繼續工作。問題是如何定義的,當執行調用的f
具體實現,並使用默認的實現(從Base
)在具體執行缺失,呼籲Base
型(不知模板)的對象的接口功能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__(https://gcc.gnu.org/onlinedocs/gcc/Function-Names.html),看看哪個函數被調用,當 – Bl4ckb0ne
您將無法檢測所有情況下的間接遞歸(例如,調用'foo'的函數調用調用函數的'bar')。 –
@ Bl4ckb0ne,如果我可以在編譯時從ImplBase :: f和PRETTY_FUNCTION實際:: f來比較PRETTY_FUNCTION,但是我認爲它不能完成,那將是一件好事。 – e271p314