以 boost type traits 在 compile time 檢查 function 的 prototype


在使用 Google C++ Mocking Framework 的時候很可能遇到一個情況,當原本的 virtual function 的 prototype 改變的時候,你所 mocking 的 prototype 很可能不是預期會被呼叫的那個。

舉例來說

#include <gmock /gmock.h>
#include <gtest /gtest.h>

class CA
{
protected:
    virtual void FuncB() {
        std::cout < < "CA FuncB" << std::endl;
    }

public:
    void FuncA() {
        FuncB();
    }
};

class CAOverrider: public CA
{
public:
    MOCK_METHOD0(FuncB, void());
};

void OverrideFuncB(){
    std::cout << "Override FuncB" << std::endl;
}

TEST(CATest, ExtractAndOverrideFuncB)
{
    using ::testing::Invoke;

    CAOverrider ca;
    EXPECT_CALL(ca, FuncB())
        .WillOnce(Invoke(OverrideFuncB));

    ca.FuncA();
}

然而有一天,有一個新同事覺得他必須傳一個參數 int 進到 FuncB 當中,就直接對於宣告與實作動了手腳,所有的測試以及 production code 都沒有問題,直到跑了這個 unit test 才發現,原本預期被呼叫的 void (CA::*)() 沒有被呼叫,實際被呼叫的是 void (CA::*)(int) 這個版本。

那麼我們可不可以直接產生出 Google Mock Framework 所需的 function prototype 呢?一開始的腦袋先動到 BOOST_TYPEOF 這個 macro,不過我馬上意識到,這樣所產生出的型別是帶有 CA::* 這樣的 member pointer,與 Google C++ Mocking Framework 所需的並不相同。

在翻過一些文章之後,我發現過去曾經有人在 boost type traits 當中加入 remove_member_pointer.hpp 這個檔案

於是關鍵的那行就可以改成

class CAOverrider: public CA
{
public:
    MOCK_METHOD0(FuncB,  boost::remove_member_pointer<boost_typeof (&CA::FuncB)>::type);
};

如此一來就能夠在編譯的時期意識到這個問題了。

回到問題的本質上,這個問題起因於 MOCK_METHOD0 並沒有辦法明確指出他有 override CA 的 FuncB。這個問題似乎也在 C++0x 的 Explicit Virtual Overrides 提出解法了。

我想這個解決方法並不是相當優雅,但也讓我開始意識到 C++ 的 template, type 以及 trait 的多樣性,也驅使我由這點再開始閱讀 Boost MPL,雖然現在才剛剛開始,但或許之後也慢慢會有不同的思維吧!

,

One response to “以 boost type traits 在 compile time 檢查 function 的 prototype”

  1. 我沒用過 gtest 所以不知道狀況,不過如果是用 boost.test 的話,每個 test case 都包成 boost::function,型別明確,所以這問題應該就不存在了。

Leave a Reply

Your email address will not be published. Required fields are marked *