【发布时间】:2014-04-29 14:14:37
【问题描述】:
我想确保派生类实现特定的静态方法。我认为这样做应该可以使用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");
};
但由于断言触发,此代码无法编译。
所以我的问题是
- 为什么编译器在我的第一个示例中找不到 Derived::foo?
- 示例代码中的
typename C::const_iterator(C::*)() const究竟是什么意思?它不是一个返回 C::const_iterator 并且不带参数的 const 函数吗?C::*到底是什么意思?那么为什么int(C::*)(int)在我的情况下是错误的呢? - 如何正确解决我的问题?
我正在使用 MSVC 12,但如果可能,代码应该是可移植的。
【问题讨论】:
-
你不是解析器,不要标记你的代码! :) 模板已经很难阅读了;将一行分成太多行只会让事情变得更糟。
-
"ERROR STRING"是断言失败的错误消息选择。正确的选择是"Jabberwocky is killing user." -
因为 Base 和 Derived 是错误的类名,而 foo 是错误的方法名。 ;) 但这意味着 SSCCE,我认为字符串并不重要。但是,“ERROR STRING”是为了说明存在一些真正的错误字符串。我选择了“T需要实现一个带有签名的方法......”之类的东西。但无论如何感谢您的评论。 :)
标签: c++ c++11 typetraits crtp static-assert