通过static_assert强制执行模板类型

时间:2013-07-16 14:27:19

标签: c++ templates template-specialization static-assert

我正在尝试理解static_assert的用处,我想知道它是否可以帮助我执行设计,如果是,那么如何。

我有一个通用模板类,它将自己的实现隐藏在另一个模板类中,该模板类根据模板类型的大小进行部分专用。以下是此设计的简要概述:

template <class T, size_t S = sizeof(T)>
struct Helper;

template <class T>
struct Helper<T, sizeof(long)>
{
    static T bar();
};

// ... other specializations ...

template <class T>
class Foo
{
public:

    T bar()
    {
        return Helper<T>::bar();
    }
};
仅当帮助程序的专业化支持T的大小时,才支持

Foo 。例如,Foo<long>Foo<unsigned long>都受支持。但是,假设用户尝试构造Foo<bool>。通常,这会产生错误,因为bool Helper 的特化没有定义,这是预期的行为。

有没有办法在此设计中使用static_assert为此界面的用户提供更多有用的错误?

此外,我还想限制用户使用特定类型,即使大小可能正确。例如,不应允许Foo<float>。现在,我知道强制执行此操作的唯一方法是通过文档中的大胆注释。 :)

3 个答案:

答案 0 :(得分:18)

如果它只能用于模板类的特化,那么让默认模板类引发一个静态断言:

template <class T, size_t S = sizeof(T)>
struct Helper
{
   static_assert(sizeof(T) == -1, "You have to have a specialization for Helper!" );
}

只有在没有更好的专业化时才会选择默认模板类,因此断言将会上升。

您可以使用相同的技术来禁止类型,但是您需要另一个模板参数来用于静态断言检查。

template <class T, class G = T, size_t S = sizeof(T)>
struct Helper
{
   static_assert(sizeof(G) == -1, "You have to have a specialization for Helper!" );
}

template <class G>
struct Helper<float,G>
{
   static_assert(sizeof(G) == -1, "You can't use float !" );
}

template <>
struct Helper<int>
{
 //This is a good specialization
};

然后你可以尝试使用这些变量:

Helper<bool> a;  //"You have to have a specialization for Helper!"
Helper<float> b; //"You can't use float !"
Helper<int> c;   //compiles OK

答案 1 :(得分:4)

http://en.cppreference.com/w/cpp/header/type_traits

std::is_base_ofstd::is_convertible可以帮助解决您的第一个问题,对于第二个问题,

static_assert(!std::is_same<float,T>(),"type can't be float");

希望这可以帮助那些偶然发现这个问题的人,假设OP可能会在被问到的4年内找到答案:)

答案 2 :(得分:0)

通过在此处结合答案和评论,我找到了解决此问题的更好解决方案。

我可以像这样定义静态类型检查器:

template <class A, class B>
struct CheckTypes
{
    static const bool value = false;
};

template <class A>
struct CheckTypes<A, A>
{
    static const bool value = true;
};

不确定标准库中是否已存在此类结构。无论如何,然后在 Foo 中,我可以使用以下方法检查类型和大小:

static_assert((sizeof(T) == sizeof(long) || sizeof(T) == sizeof(int)) && !CheckTypes<T, float>::value, "Error!");