C++ static_assert 与 class 模板参数
C++ static_assert with class template argument
想做一些静态dispatch的工作,让baseclassstatic_castthis
指针指向derivedclass调用同名函数实现多态.我还想用 static_assert
来确保派生的 class 确实重载了特定的功能(否则会死循环)。我尝试将 static_assert 放在三个位置,但令人惊讶的是发现并非所有位置都有效。
#include <iostream>
template<typename Type, Type Ptr>
struct MemberHelperClass;
#define DEFINE_HAS_MEMBER_FUNCTION(func) \
template<typename T, typename Type> \
static char MemberHelper_##func(MemberHelperClass<Type, &T::func>*); \
template<typename T, typename Type> \
static int MemberHelper_##func(...); \
template<typename T, typename Type> \
struct has_member_##func { \
static constexpr bool value = sizeof(MemberHelper_##func<T, Type>(nullptr)) == sizeof(char); \
};
#define STATIC_ASSERT_HAS_MEMBER_FUNCTION(T_, F_, func) \
static_assert(has_member_##func<T_, F_>::value == 1, "function `"#func"` is undefined or inaccessible"); \
template<typename D>
class B
{
public:
DEFINE_HAS_MEMBER_FUNCTION(f);
// 1.??? why this assert always fail even if D::f is present
// STATIC_ASSERT_HAS_MEMBER_FUNCTION(D, void(D::*)(), f);
void f() {
// 2.ok, assert fails only when B::f is called but D::f is not defined
// STATIC_ASSERT_HAS_MEMBER_FUNCTION(D, void(D::*)(), f);
static_cast<D*>(this)->f();
}
protected:
B() {
// 3.ok, assert fails only when instance of D is declared but D::f is not defined
// STATIC_ASSERT_HAS_MEMBER_FUNCTION(D, void(D::*)(), f);
}
};
class D : public B<D>
{
public:
// void f() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
template<typename T>
void g(B<T>* pB)
{
pB->f();
}
int main()
{
D d;
g(&d); // should print void D::f()
return 0;
}
那么为什么第一个 static_assert 总是失败?我认为这将是最好的选择,因为不需要调用 f
。而且classD只需要声明,不需要D的实例...
在 B<D>
的定义被隐式实例化时,D
是不完整的。因此,B
的 class 定义中的 static_assert
将不会在 D
的定义中看到任何内容。成员函数体仅在使用时隐式实例化,此时D
已经完成
class D : public B<D> // <--- B<D> implicitly instantiated here
{
public:
// void f() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
}; // <--- D becomes complete here
想做一些静态dispatch的工作,让baseclassstatic_castthis
指针指向derivedclass调用同名函数实现多态.我还想用 static_assert
来确保派生的 class 确实重载了特定的功能(否则会死循环)。我尝试将 static_assert 放在三个位置,但令人惊讶的是发现并非所有位置都有效。
#include <iostream>
template<typename Type, Type Ptr>
struct MemberHelperClass;
#define DEFINE_HAS_MEMBER_FUNCTION(func) \
template<typename T, typename Type> \
static char MemberHelper_##func(MemberHelperClass<Type, &T::func>*); \
template<typename T, typename Type> \
static int MemberHelper_##func(...); \
template<typename T, typename Type> \
struct has_member_##func { \
static constexpr bool value = sizeof(MemberHelper_##func<T, Type>(nullptr)) == sizeof(char); \
};
#define STATIC_ASSERT_HAS_MEMBER_FUNCTION(T_, F_, func) \
static_assert(has_member_##func<T_, F_>::value == 1, "function `"#func"` is undefined or inaccessible"); \
template<typename D>
class B
{
public:
DEFINE_HAS_MEMBER_FUNCTION(f);
// 1.??? why this assert always fail even if D::f is present
// STATIC_ASSERT_HAS_MEMBER_FUNCTION(D, void(D::*)(), f);
void f() {
// 2.ok, assert fails only when B::f is called but D::f is not defined
// STATIC_ASSERT_HAS_MEMBER_FUNCTION(D, void(D::*)(), f);
static_cast<D*>(this)->f();
}
protected:
B() {
// 3.ok, assert fails only when instance of D is declared but D::f is not defined
// STATIC_ASSERT_HAS_MEMBER_FUNCTION(D, void(D::*)(), f);
}
};
class D : public B<D>
{
public:
// void f() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
template<typename T>
void g(B<T>* pB)
{
pB->f();
}
int main()
{
D d;
g(&d); // should print void D::f()
return 0;
}
那么为什么第一个 static_assert 总是失败?我认为这将是最好的选择,因为不需要调用 f
。而且classD只需要声明,不需要D的实例...
在 B<D>
的定义被隐式实例化时,D
是不完整的。因此,B
的 class 定义中的 static_assert
将不会在 D
的定义中看到任何内容。成员函数体仅在使用时隐式实例化,此时D
已经完成
class D : public B<D> // <--- B<D> implicitly instantiated here
{
public:
// void f() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
}; // <--- D becomes complete here