boost::enable_if 带算术表达式

boost::enable_if with arithmetic expression

我有一个自定义字符串 class,其长度作为专业化参数。长度应至少为 9 个字符,我想将其作为编译时检查。

我希望为此使用 boost::enable_if,但我很难理解语法。我希望有类似 boost::is_greater 的内容,类似于 boost::same_as,如下所示。但是我找不到要放入 enable_if 模板参数的表达式。有人可以帮忙吗?

不幸的是我不能为此使用 C++11。

#include <stdio.h>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits.hpp>

template<int LEN, class Enable = void>
class MyString
{
public:
    char data[LEN];
};

template<int LEN, typename boost::enable_if<boost::is_greater<LEN, 8>::type> >
class MyString
{
};

int main()
{
    MyString<4> s;
    return snprintf(s.data, 4, "123");
}

boost::enable_if 允许利用 SFINAE,这在某些情况下可能有用,但在其他情况下不合适。通常,当您希望根据某些条件禁用某些代码分支而不产生硬编译错误时,您希望使用 SFINAE,这通常意味着该情况将由另一个分支处理。例如,可以 select 根据某些条件调用函数重载。

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_ifboost::disable_if 接受元函数作为其第一个模板参数。元函数是一个 class,它有一个嵌套的静态成员变量 value,这是元函数的结果。 Boost 还提供 boost::enable_if_cboost::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 嵌套类型。对于 classes,这基本上相当于专业化中的模板参数列表。
// 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 >
{
};

所以这段代码有效地 selects 专业化取决于条件。如果你想让 MyString 只在满足条件的情况下工作,你可以不定义主模板(即只保留声明):

// Generic template. Used whenever none of the specializations apply.
template< int LEN, class Enable = void >
class MyString;

如果您确实只想在违反某些编译时先决条件时生成硬错误,则使用静态断言可能更合适。在 C++11 中,它是用 static_assert, in C++03 you can use Boost.StaticAssert:

完成的
template< int LEN >
class MyString
{
    BOOST_STATIC_ASSERT_MSG(LEN > 8, "String length must be greater than 8");
};

在这种情况下,不需要专门化,作为额外的好处,您会收到更好的错误消息。在 C++03 中,它会说一些关于静态断言失败的事情,指向断言行,它用通俗易懂的语言解释了问题。在 C++11 中,编译器错误将包含内联消息。