【问题标题】:Enforce template type through static_assert通过 static_assert 强制执行模板类型
【发布时间】:2013-07-14 19:04:35
【问题描述】:

我正在尝试了解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 仅在 Helper 的特化支持 T 的大小时才受支持。例如,Foo&lt;long&gt;Foo&lt;unsigned long&gt; 都受支持。然而,假设用户试图构造一个Foo&lt;bool&gt;。通常,这会产生错误,因为未定义 boolHelper 特化,这是预期的行为。

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

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

【问题讨论】:

  • 更笼统地思考一下,它只是支持整数类型吗?没有charboolfloat 等?
  • 在 SO 中搜索模板类型约束或“概念”。在最后一刻从 C++11 中删除了执行此操作的工具。不过,实现类似结果的自动化方法较少。
  • @Rapptz、charintlong 以及它们的 unsigned 版本应受支持。如果sizeof(int) == sizeof(long) == sizeof(unsigned long)intlongunsigned long 的代码将相同。

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


【解决方案1】:

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

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

【讨论】:

  • 我相信你想要static_assert(false,...),所以它总是会跳闸。 static_assert 如果第一个参数为假,则打印错误。
  • 这不会按原样工作-您需要使断言依赖(例如static_assert(sizeof(T) == 0, ...);),否则它会在声明点进行处理,而不是实例化。
  • @Angew 你检查了吗?我希望它一开始会在 浅实例化 时触发。纳米我检查了:你是对的 :)
  • 我刚刚尝试了这个解决方案,但它不起作用。无论是否使用默认特化,它总是引发一个断言。不确定这种行为是否依赖于编译器。
  • @Zeenobit 我已更改解决方案以使其正常工作。需要添加另一个“不可见”的模板参数
【解决方案2】:

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

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

static_assert(!std::is_same&lt;float,T&gt;(),"type can't be float");

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

【讨论】:

  • 我必须在 VS2010 中执行 std::is_same&lt;X, Y&gt;::value 以避免 C2057 预期的常量表达式错误。
【解决方案3】:

通过结合这里的答案和 cmets,我想出了一个更好的解决方案。

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

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

【讨论】:

  • 确实如此,std::is_same
  • 使用 sizeof 并不安全。这只是大小。 long 和 int 的大小可能相同,仅包含 int 的随机结构也将具有相同的大小。
猜你喜欢
  • 2021-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-01
  • 1970-01-01
  • 2012-01-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多