将"stored"可变参数模板类型解压缩为模板参数

Unpacking "stored" variadic template types into template parameters

本文关键字:参数 类型 解压缩 stored 变参      更新时间:2023-10-16

我正在尝试编写模拟以用于单元测试。为此,我需要反映我无法更改的库的真实实现。这是一个非常简单的示例:

Library CodeIcantChange.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> {};

但是,我想从真实的界面列表中推断出接口列表,而不是复制它。我可以在一个接口上使用它,但是我需要一组接口的模板参数。我将variadic类型存储到我称为 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

我想做的是可能的吗?如果是这样,如何?

因此,据我了解您的问题,它归结为此起点:

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;
}