boost::enable_if 允许利用SFINAE,这在某些情况下可能会有所帮助,而在其他情况下则不合适。通常,当您想根据某些条件禁用某些代码分支而不产生硬编译错误时,您希望使用 SFINAE,这通常意味着该案例将由另一个分支处理。例如,可以根据某些条件选择要调用的函数重载。
struct A {};
// This overload gets called for any type T that derives from A or for A itself
template< typename T >
typename boost::enable_if< typename boost::is_base_of< A, T >::type >::type
foo(T const& t);
// This overload is selected for any other types
template< typename T >
typename boost::disable_if< typename boost::is_base_of< A, T >::type >::type
foo(T const& t);
关于你的例子,有几点需要注意:
- 与 C++11 中的
std::enable_if 不同,boost::enable_if 和 boost::disable_if 接受元函数作为其第一个模板参数。元函数是具有嵌套静态成员变量value 的类,它是元函数的结果。 Boost 还提供了boost::enable_if_c 和boost::disable_if_c 模板,它们和std::enable_if 一样,直接接受布尔常量。所以,如果你想检查长度是否大于8,你可以简单地写:
typename boost::enable_if_c< (LEN > 8) >::type
请注意,将条件放在括号中以避免解析错误,因为更大的运算符将被解释为右尖括号。
- 一些损坏的编译器会出现上述常量表达式的问题。对于那些编译器,可能需要将条件表示为元函数。 Boost.MPL 可以帮助您:
typename boost::enable_if<
boost::mpl::greater<
boost::mpl::int_< LEN >,
boost::mpl::int_< 8 >
>
>::type
这里,boost::mpl::greater 是产生比较结果的元函数;此结果由boost::enable_if 获取。
- 无论您使用哪种形式,在模板参数替换失败会使声明无效的上下文中使用
enable_if<>::type 嵌套类型非常重要。对于类,这基本上相当于专业化中的模板参数列表。
// Generic template. Used whenever none of the specializations apply.
template< int LEN, class Enable = void >
class MyString
{
};
// Specialization. Used if LEN > 8 is true because
// its second template argument (Enable, which is void by default)
// matches the type produced by enable_if_c, which is also void
// if the condition is true.
template< int LEN >
class MyString< LEN, typename boost::enable_if_c< (LEN > 8) >::type >
{
};
因此,此代码有效地根据条件选择专业化。如果您希望 MyString 仅适用于满足条件的情况,您可以不定义主模板(即仅保留声明):
// Generic template. Used whenever none of the specializations apply.
template< int LEN, class Enable = void >
class MyString;
如果您真的想在违反某些编译时前提条件时仅生成硬错误,则使用静态断言可能更合适。在 C++11 中使用 static_assert 完成,在 C++03 中可以使用 Boost.StaticAssert:
template< int LEN >
class MyString
{
BOOST_STATIC_ASSERT_MSG(LEN > 8, "String length must be greater than 8");
};
在这种情况下,不需要专业化,并且作为额外的奖励,您将获得更好的错误消息。在 C++03 中,它会说一些关于静态断言失败的内容,指向断言行,用通俗的语言解释问题。在 C++11 中,编译器错误将包含内联消息。