我正在尝试编写模拟以用于单元测试。要做到这一点,我需要镜像我无法改变的库的实际实现。这是一个非常简单的例子:
LibraryCodeICantChange.h:
struct IFoo {};
struct IBar {};
template<typename... I>
struct implements {};
template<typename... I>
struct mocks {};
struct CRealSingle : implements<IFoo> {};
struct CRealMulti : implements<IFoo, IBar> {};
简单地说,我的嘲讽就是这样:
#include "LibraryCodeICantChange.h"
struct CMockSingle : mocks<IFoo> {};
struct CMockMulti : mocks<IFoo, IBar> {};
但是,我想从真实中推断出接口列表,而不是重复它。我让它适用于单个界面,但我需要一组可变的接口模板参数。我将可变参数类型存储到一个名为pack
的结构中,但我不知道如何解压缩这些类型:
#include "LibraryCodeICantChange.h"
template<typename... I>
struct pack {};
// just declared, not defined: only used for typing
template<typename... I>
pack<I...> steal_real_params(implements<I...>*);
template<typename C>
using steal_real_params_t = decltype(steal_real_params(std::declval<C*>()));
template<typename C>
struct MockBasedOnReal: mocks<steal_real_params_t<C>... /* how to unpack? */> {};
// error C3546: '...': there are no parameter packs available to expand
struct CMockSingle : MockBasedOnReal<CRealSingle> {}; // error while 'MockBasedOnReal<CRealSingle>' being compiled
struct CMockMulti : MockBasedOnReal<CRealMulti> {}; // error while 'MockBasedOnReal<CMockMulti>' being compiled
我正在尝试做什么?如果是这样,怎么样?
答案 0 :(得分:1)
所以,正如我理解你的问题,它归结为这个起点:
struct CRealMulti : implements<IFoo, IBar> {};
并且您希望有一个模板,您可以将此CRealMulti
类提供给,然后能够派生从mocks<Ifoo, IBar>
继承的内容。用gcc 7.1.1测试:
#include <utility>
struct IFoo {};
struct IBar {};
struct IBaz {};
template<typename... I>
struct implements {};
template<typename... I>
struct mocks {};
struct CRealSingle : implements<IFoo> {};
struct CRealMulti : implements<IFoo, IBar> {};
// Given a subclass of implements<I...>, extract it:
template<typename ...I>
implements<I...> return_implements(implements<I...> &&);
// Specialization to extract the parameter pack:
template<typename T> struct implements_to_mocks;
template<typename ...I>
struct implements_to_mocks<implements<I...>> {
typedef mocks<I...> mocks_t;
};
// All the hard work is here:
template<typename C> struct to_mock {
typedef decltype(return_implements(std::declval<C &&>())) implements_t;
typedef typename implements_to_mocks<implements_t>::mocks_t type;
};
// to_mock_t provides a convenient shortcut
template<typename T>
using to_mock_t=typename to_mock<T>::type;
// The end result:
//
// to_mock_t<CRealMulti> is an alias for mocks<IFoo, IBar>, ready
// and waiting to be inherited from.
void foo()
{
typedef std::enable_if<std::is_same<
to_mock_t<CRealMulti>, mocks<IFoo, IBar>>::value>::type t;
}