我想确保派生类实现特定的静态方法。我认为应该可以使用static_assert,std::is_same,decltype,CRTP并使用SFINAE来实现这一目标。但是,到目前为止我发现的similar code非常复杂,似乎我还没有完全理解它使我无法将其用于我的需要。
到目前为止我尝试的是
template <class T>
class Base
{
static_assert(std::is_same<decltype(T::foo(1)), int>::value, "ERROR STRING");
};
class Derived : public Base <Derived>
{
public:
static int foo(int i) { return 42; };
};
然而,它没有编译告诉我,即使方法正确实现,Derived也没有名为foo的元素。此外,在static_assert内的表达式中为foo提供实际参数会感觉不对。
搜索SO显示了一个类似的问题,最终导致我this piece of code,检查类型是否有方法begin()和end()返回迭代器。所以我试着根据我的需要采用这个代码。
template <class T>
class Base
{
template<typename C>
static char(&g(typename std::enable_if<std::is_same<decltype(static_cast<int(C::*)(int)>(&C::foo)), int(C::*)(int)>::value, void>::type*))[1];
template<typename C>
static char(&g(...))[2];
static_assert(sizeof(g<T>(0)) == 1, "ERROR STRING");
};
但是这段代码没有编译,因为断言会触发。
所以我的问题是
typename C::const_iterator(C::*)() const
究竟是什么意思?是不是一个const函数返回C :: const_iterator并且没有参数? C::*
究竟是什么意思?那么为什么int(C::*)(int)
在我的情况下会出错?我正在使用MSVC 12,但如果可能,代码应该是可移植的。
答案 0 :(得分:12)
使用CRTP时这是一个常见问题:Base<Derived>
会在Derived
的基础列表中遇到Derived
时被实例化,此时static_assert
是还没有一个完整的类型,因为其声明的其余部分尚未被解析。有各种解决方法。对于Derived
,您需要延迟断言的实例化,直到Base
完成。一种方法是将断言放在template <class T>
class Base
{
public:
~Base() {
static_assert(std::is_same<decltype(T::foo(1)), int>::value, "ERROR STRING");
}
};
class Derived : public Base<Derived>
{
public:
static int foo(int) { return 42; };
};
的成员函数中,你知道必须将其实例化 - 析构函数总是一个不错的选择(Live at Coliru):
C::*
解决问题#2:C
是&#34;指向类int(*)(int)
成员的指针的语法。&#34;所以int
是&#34;指向函数的指针,它接受一个int
参数并返回int(C::*)(int)
&#34;,而C
类似于&#34;指向成员的指针int
获取单个int
参数并返回typename C::const_iterator(C::*)() const
的函数。&#34;怪物
C
将转换为&#34;指向C::const_iterator
的常量成员函数的指针,不带参数并返回typename
&#34;当然,C::const_iterator
必须表明依赖名称{{1}}是一种类型。