【发布时间】:2021-10-15 19:11:52
【问题描述】:
当我第一次听说 C++20 约束和概念时,我真的很兴奋,到目前为止,我在测试它们时获得了很多乐趣。最近想看看能不能用C++20的概念来测试类或者函数的约束。例如:
template <int N>
requires (N > 0)
class MyArray { ... };
template <int N>
concept my_array_compiles = requires {
typename MyArray<N>;
};
my_array_compiles<1>; // true
my_array_compiles<0>; // false
起初我没有任何问题,但我遇到了一个情况,即依赖函数中的 static_assert 会阻止编译,即使它出现在 requires 表达式中也是如此。下面是一个例子来说明这一点:
template <bool b>
requires b
struct TestA {
void foo() {}
};
template <bool b>
struct TestB {
static_assert(b);
void foo() {}
};
template <template<bool> class T, bool b>
concept can_foo = requires (T<b> test) {
test.foo();
};
can_foo<TestA, true>; // true
can_foo<TestA, false>; // false
can_foo<TestB, true>; // true
// can_foo<TestB, false>; does not compile
TestA 和 TestB 在大多数用例中应该类似地工作(尽管我发现 TestB
template <class T>
concept has_element_0 = requires {
typename tuple_element_t<0, T>;
};
has_element_0<tuple<int>>; // true
// has_element_0<tuple<>>; does not compile
当我将一个空元组传递给上述概念时,我收到错误static_assert failed due to requirement '0UL < sizeof...(_Types)' "tuple_element index out of range"。我已经在 g++ 10.3.0 和 clang 12.0.5 上对此进行了测试。我可以通过提供一个使用约束的包装器来解决这个问题,但这在某种程度上违背了目的,因为我实际上是通过在更高级别强制执行相同的条件来阻止编译器看到 static_assert。
template <size_t I, class T>
requires (I >= 0) && (I < tuple_size_v<T>)
using Type = tuple_element_t<I, T>;
template <class T>
concept has_element_0 = requires {
typename Type<0, T>;
};
has_element_0<tuple<int>>; // true
has_element_0<tuple<>>; // false
根据 std::tuple_element 的使用方式,它并不总是有效:
template <size_t I, class T>
requires (I >= 0) && (I < tuple_size_v<T>)
tuple_element_t<I, T> myGet(const T& tup) {
return get<I>(tup);
}
template <class T>
concept has_element_0 = requires (T tup) {
myGet<0>(tup);
};
has_element_0<tuple<int>>; // true
// has_element_0<tuple<>>; does not compile
所以最终我的问题是:这种需要表达式的预期行为是否不考虑 static_assert ?如果是这样,这种设计的原因是什么?最后,是否有更好的方法可以在不使用上述解决方法的情况下使用 static_assert 实现我的类目标?
感谢阅读。
【问题讨论】:
-
与sfinae 一样,仅捕获“即时上下文”中的错误。大概是为了避免在大型模板上进行检查过于昂贵。
-
@HolyBlackCat 我相信您的回答是正确的,但标准中的哪个地方这么说?
-
@Barry 我没有看到任何暗示它在约束检查期间适用的内容。 “替换发生在函数类型和模板参数声明中使用的所有类型和表达式中。”要求表达式通常不会出现在这些地方。
标签: c++ templates c++20 c++-concepts type-constraints