【问题标题】:C++: using a static_assert in a template aliasC++:在模板别名中使用 static_assert
【发布时间】:2019-07-10 08:42:34
【问题描述】:

是否可以将static_assert 与模板别名结合使用?我了解如何使用带有模板别名的 SFINAE,以及如何使用带有 structstatic_assert,但我希望带有别名的 static_assert 能够提供更清晰的错误消息。

我想到了以下用例:

#include <array>

constexpr bool is_valid(int n){
    return n <= 10;
}

template <int n>
struct Foo {
    static_assert(is_valid(n), "This class cannot handle more than 10 dimensions");
};

template <int n>
using Bar = std::array<float,n>;  

template <int n, std::enable_if_t<is_valid(n)> * unused = nullptr>
using BarSFINAE = std::array<float,n>;  

int main() {

    Foo<5>();
    // Foo<20>(); // Triggers the compiler-time static_assert

    Bar<5>();
    Bar<20>(); // TODO: Should trigger a compiler-time static_assert

    BarSFINAE<5>();
    // BarSFINAE<20>(); // Not allowed due to SFINAE, but throws an ugly compile time message
}

问题本质上是别名没有正文。所以我什至不知道我会把static_assert放在哪里。

【问题讨论】:

  • 我很好奇为什么static_assert 只适用于别名。对于仅使用别名类型/模板的人来说,这是一个非常薄的安全层。要么您可以控制别名类型/模板(在这种情况下,只需在那里进行检查?)或者您没有(在这种情况下,您不能轻易阻止其他人忽略您的别名)...
  • 为什么不直接template &lt;int n&gt; using Bar = std::enable_if_t&lt;is_valid(n), std::array&lt;float, n&gt;&gt;?顺便说一句,非类型模板参数在 C++14 中不应具有 void* 类型。
  • @MaxLanghof 我们正在编译一个用于分发的库。显然,用户可以只修改这个头文件并删除静态断言,但是他们会得到奇怪的链接器错误,因为库只是针对特定条件编译的
  • @L.F.我不明白你对 void 的看法*
  • @bremen_matt 使用其他类型,例如int

标签: c++ c++14


【解决方案1】:

当您正确识别问题时,解决方案是添加具有别名可以依赖的正文的内容。例如,一个函数。

namespace detail {
    template<std::size_t N>
    constexpr auto checked_size() {
        static_assert(is_valid(N), "");
        return N;
    }
}

template <int n>
using Bar = std::array<float, detail::checked_size<n>()>;  

【讨论】:

  • std::enable_if 几乎为我们做了这件事。 template &lt;int n&gt; using Bar = std::enable_if_t&lt;detail::checked_size&lt;n&gt;(), std::array&lt;float, n&gt;&gt;; 实际上是一样的。
  • @L.F. - 禁止自定义错误消息,这是我认为的 OP。 enable_if 只会给您留下一个令人困惑的错误,即未定义某些内容。
【解决方案2】:

是的,您可以使用这样的辅助结构来做到这一点:

template<typename T>
struct A {};

template<int n, typename T>
struct B_impl {
  static_assert(n <= 10,
      "this is a demonstration");
  using type = A<T>;
};

template<int n, typename T>
using B = typename B_impl<n, T>::type;

using B_good = B<3, int>;

using B_bad = B<11, int>;

int main() {
  B_good good; // works
  B_bad bad; // static assertion failure
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-12
    • 1970-01-01
    • 1970-01-01
    • 2019-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多