NoS*_*tAl 6 c++ type-traits c++-concepts c++20
问题可能很奇怪,所以这里是一个简短的激励示例:
#include <vector>
#include <type_traits>
template <typename T>
// workaround for gcc 8.3 where volatile int is not trivially copyable
using is_tc = std::is_trivially_copyable<std::remove_cv<T>>;
// static assert passes compile, oops
static_assert(is_tc<std::vector<int>>::value);
Run Code Online (Sandbox Code Playgroud)
如您所见,错误在于我将类型特征本身传递给另一个类型特征,而不是传递::type或使用std::remove_cv_t.
明显的解决方案是我不要犯错误,但我想知道 C++ 类型特征是否可以限制它们的输入类型,以便它们不接受其他 type_traits 作为参数。现在困难的是 type_traits 中有大量类型特征,所以 IDK 如何最好地实现这一点。
注意:我不是说 C++ 应该这样做,我知道要防止罕见的错误需要做很多工作,我只是想了解更复杂的概念设计,其中您的限制不基于类型的语义(又名具有 ++和 *) 但事实上类型属于一个庞大的类型集(并且该集包括您限制的类型)。
std概念:是在命名空间中声明的TransformationTrait我想知道是否有一种方法 C++ 类型特征可以限制它们的输入类型,以便它们不接受其他 type_traits
由于元函数特征实际上是类型本身(这也是问题的根源),我们可以利用这一点并构建一个概念,以确定T参数依赖查找 (ADL) 是否可以通过 ADL 找到较小的STL 函数选择集在类型的对象上T(在非评估上下文中),其中T可能是元功能特征;本质上是一种基于 ADL(可能很脆弱 - 见下文)的机制,用于查询给定类型是否T在命名空间中定义std,而不是查询是否T恰好是std命名空间中定义的众多特征类型之一的详细方法。
如果我们将其与TransformationTrait要求结合起来:
C++ 命名需求:TransformationTrait
TransformationTrait是一个类模板,提供其模板类型参数的转换。
要求:
- 采用一个模板类型参数(其他模板参数是可选且允许的)
- 转换后的类型是一个可公开访问的嵌套类型,名为
type
我们可以为类型构造一个通用概念,T作为命名空间中的转换特征std。但请注意,如果由于某种原因给定项目开始声明重载 STL 中函数名称的函数,那么在这种意义上依赖 ADL 可能会有些脆弱。在可能的 ADL 查找概念中扩展较小的 STL 函数选择集将使非实现者的观点更难突破std。
例如定义几个概念如下:
namespace traits_concepts {
template <typename T>
concept FindsStlFunctionByAdlLookupOnT = requires(T t) {
// Rely on std::as_const being found by ADL on t, i.e.
// for t being an object of a type in namespace std.
as_const(t);
// If we are worried that a user may define an as_const
// function in another (reachable/found by lookup)
// namespace, expand the requirement with additional
// STL functions (that can be found via ADL).
move(t);
// ...
// Remember to add the appropriate includes.
};
template <typename T>
concept IsTransformationTrait = requires {
// REQ: The transformed type is a publicly accessible
// nested type named type.
typename T::type;
};
template <typename T>
concept IsStlTransformationTrait =
IsTransformationTrait<T> && FindsStlFunctionByAdlLookupOnT<T>;
template <typename T>
concept IsNotStlTransformationTrait = !IsStlTransformationTrait<T>;
} // namespace traits_concepts
Run Code Online (Sandbox Code Playgroud)
应用于:
namespace not_std {
template <traits_concepts::IsNotStlTransformationTrait T>
struct NotAnStlTrait {
using type = T;
};
struct Foo {};
}; // namespace not_std
// Is an STL transformation trait
static_assert(
traits_concepts::IsStlTransformationTrait<std::remove_cv<const int>>);
// Is not an STL transformation trait.
static_assert(
!traits_concepts::IsStlTransformationTrait<std::remove_cv_t<const int>>);
static_assert(
!traits_concepts::IsStlTransformationTrait<not_std::NotAnStlTrait<int>>);
static_assert(!traits_concepts::IsStlTransformationTrait<not_std::Foo>);
int main() {}
Run Code Online (Sandbox Code Playgroud)
并且,对于添加到的自定义特征std(假设现在我们是编译器供应商;将名称添加到std命名空间是 UB):
namespace std {
// Assume we are a compiler vendor.
// (Adding names to the std namespace is UB).
template <traits_concepts::IsNotStlTransformationTrait T>
struct custom_stl_trait {
using type = T;
};
}; // namespace std
static_assert(
traits_concepts::IsStlTransformationTrait<std::custom_stl_trait<int>>);
static_assert(!traits_concepts::IsStlTransformationTrait<
std::custom_stl_trait<int>::type>);
int main() {}
Run Code Online (Sandbox Code Playgroud)
演示。
| 归档时间: |
|
| 查看次数: |
256 次 |
| 最近记录: |