是否可以将类型特征限制为不接受其他类型特征作为参数? [英] Could type traits be restricted to not accept other type traits as arguments?

查看:74
本文介绍了是否可以将类型特征限制为不接受其他类型特征作为参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题可能很奇怪,所以这里是一个简短的激励示例:

Question may be weird so here is a brief motivational example:

#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);

您可以看到错误是我将类型特征本身传递给了另一个类型特征,而不是传递了 :: type 或使用了 std :: remove_cv_t .

As you can see mistake is that I have passed the type trait itself to another type trait instead of passing ::type or using std::remove_cv_t.

对我来说,显而易见的解决方案是不要犯错误,但是我想知道C ++类型特征是否可以限制它们的输入类型,以便它们不接受其他type_traits作为参数.现在的困难是,在type_traits中有大量的类型特征,因此IDK如何最好地实现这一点.

Obvious solution is for me to not make mistakes, but I wonder if is there a way C++ type traits could restrict their input types so that they do not accept other type_traits as arguments. Now the hard thing is that there is a huge set of type traits in type_traits so IDK how would one go best about implementing this.

注意:我并不是说C ++应该这样做,我知道要防止罕见的错误需要做很多工作,我只是想学习更复杂的概念设计,而您的约束并不基于类型的语义(aka具有++和*),但实际上类型属于大量类型(并且该类型包含您要限制的类型).

Note: I am not saying C++ should do this, I know it is a lot of work to prevent rare bugs, I am just trying to learn about more complicated concepts design where your restriction is not based on semantics of types(aka has ++ and *) but on the fact that types belong to a huge set of types(and that set includes the type you are restricting on).

推荐答案

概念:是在 std 命名空间中声明的TransformationTrait

Concept: Is a TransformationTrait declared in the std namespace

我想知道C ++类型特征是否可以限制它们的输入类型,以使它们不接受其他type_traits

I wonder if is there a way C++ type traits could restrict their input types so that they do not accept other type_traits

由于元功能特征本身实际上是类型(这也是问题的根源),因此我们可以利用它并为 T 构造一个概念,以确定参数依赖查找(ADL)是否可以在类型为 T 的对象上(通过未评估的上下文),通过ADL查找STL函数的较小选择集.可能是元功能特征;本质上是一种基于ADL的机制(可能很脆弱-参见下文),用于查询是否在 std 命名空间中定义了给定类型的 T ,这与冗长的方法相反.查询 T 是否正好是 std 命名空间中定义的众多特征类型之一.

Since metafunction traits are actually types themselves (which is kind of also the root of your problem), we can leverage this and construct a concept for T for whether Argument-Dependent Lookup (ADL) can find a smaller select set of STL-functions via ADL on an object of type T (in a non-evaluated context), where T may potentially be a metafunction trait; essentially an ADL-based (possibly brittle - see below) mechanism to query whether a given type T is defined in the std namespace or not, as opposed to the verbose approach of querying whether T is exactly one of numerous trait types defined in the std namespace.

如果我们将其与 TransformationTrait 要求结合起来:

If we combine this with the TransformationTrait requirement:

C ++命名要求: TransformationTrait

TransformationTrait 是一个类模板,提供了其模板类型参数的转换.

C++ named requirements: TransformationTrait

A TransformationTrait is a class template that provides a transformation of its template type parameter.

要求:

  • 采用一个模板类型参数(其他模板参数是可选的,并且允许)
  • 转换后的类型是一个可公开访问的嵌套类型,名为 type

我们可以为类型 T 构建通用概念,该类型是 std 命名空间中的转换特征.但是请注意,如果给定的项目出于某种原因开始声明使STL中的函数名超载的函数,则从某种意义上说依赖ADL可能会有些脆弱.在概念中扩展 STL函数的较小选择集以进行可能的ADL查找,将使从非 std -实现者的角度来看更难以突破.

we can construct a common concept for a type T being a transformation trait in the std namespace. Note however that relying on ADL in this sense can be somewhat brittle, if for some reason a given project starts to declare functions which overloads function names from the STL. Expanding the smaller select set of STL-functions in the concept for possible ADL-lookup will make it harder to break from a non-std-implementor perspective.

例如定义了一些概念,如下所示:

E.g. defining a few concepts as follows:

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

应用于:

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() {}

并且,对于添加到 std 的自定义特征(假设现在我们是编译器供应商;将名称添加到 std 命名空间为UB):

And, for a custom trait added to std (assume for now that we are a compiler vendor; adding names to the std namespace is 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() {}

演示 .

这篇关于是否可以将类型特征限制为不接受其他类型特征作为参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆