通过static_assert强制执行模板类型

Enforce template type through static_assert

本文关键字:类型 强制执行 assert static 通过      更新时间:2023-10-16

我正在努力理解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();
    }
};

Foo仅当T的大小由Helper的专用化支持时才受支持。例如,同时支持Foo<long>Foo<unsigned long>。但是,假设用户试图构建一个Foo<bool>。通常,这会产生错误,因为boolHelper的专门化没有定义,这是预期行为。

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

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

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

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

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年内找到了答案:)

我把这里的答案和注释结合起来,为这个问题找到了更好的解决方案。

我可以定义一个静态类型检查器,如下所示:

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!");