【发布时间】:2015-11-11 21:38:23
【问题描述】:
我已经实现了一个像这样的元编程成员检查器:
//Declare a metaprogramming test to check if a class has a member
//of a given signature and a certain name
#define DECL_hasMember(MEMBER) \
/* Check if T has member MEMBER M is a pointer to member of T type (T::*) */ \
template <typename T, typename M> \
class hasMember_##MEMBER { \
private: \
typedef char passed[1]; \
typedef char failed[2]; \
\
template <typename U, U> struct reallyHas; \
\
template <typename C> static passed& test(reallyHas<M, &C::MEMBER>*); \
template <typename C> static failed& test(...); \
\
hasMember_##MEMBER()=delete; \
public: \
static bool const value = sizeof(test<T>(nullptr)) == sizeof(passed); \
}
我已经在许多情况下对此进行了测试,并且检查器在大多数情况下都可以正常工作,
现在我正在使用奇怪的重复模板模式实现一个有限状态机,它有一个将状态与派生类的函数相关联的映射。我希望这个派生类有一个名为 buildFSM 的成员,创建所述地图。我想使用静态断言强制执行此操作,以获得更好的编译器错误。但是元编程检查器似乎无法检测到desc_t
(为了这个问题,我试图在一个更简单的场景中复制这种情况,但无法让它在不同的上下文中失败)
DECL_hasMember(buildFSM);
template<class Executor_T, typename State_T = uint32_t, typename ... Args>
class FSM
{
public:
typedef State_T state_t;
typedef FSM<Executor_T, State_T, Args...> fsm_t;
protected:
/* returns the next state */
typedef state_t (Executor_T::*handler_t)(Args...);
/* holds all the states */
struct desc_t : private std::map<state_t, handler_t> {
friend fsm_t;
void addState(const state_t&, handler_t);
using std::map<state_t, handler_t>::size;
using std::map<state_t, handler_t>::empty;
};
private:
/* Implementation must implement buildFSM returning a desc_t that initializes this */
static desc_t states;
static_assert(hasMember_buildFSM<Executor_T, desc_t(Executor_T::*)()>::value,
"Implementing class must provide desc_t buildFSM() function member.");
/* [...] */
};
//Delegate the initialization of states to the derived class
template<class E, typename S, typename ... A>
decltype(FSM<E, S, A...>::states) FSM<E, S, A...>::states= std::move(E::buildFSM());
struct test : public FSM<test> {
fsm_t::desc_t buildFSM() {
return fsm_t::desc_t();
}
};
正如我之前所说,静态断言失败,即它无法检测到test::buildFSM。问题出在desc_t,因为如果我将其更改为另一种类型,则测试通过就好了。如果我修改desc_t 使其不派生std::map,则测试也通过了。为什么会这样?在这种情况下,我能做些什么来完成这项工作吗?我知道另一种选择是将地图作为成员而不是基类,但我不明白为什么会发生这种情况。
我在 Visual Studio 2015 中。
【问题讨论】:
-
我也在 Visual Studio 2015 中,这导致我的编译器崩溃。我不再感到惊讶了。
-
这不会在 Clang 或 GCC 中编译,这不足为奇;在
FSM<test>实例化时,test是一个不完整的类型,但您的static_assert检查其成员,这当然会失败。
标签: c++ templates metaprogramming