首页 > 解决方案 > 类型特征是否可以限制为不接受其他类型特征作为参数?

问题描述

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

#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.

明显的解决方案是让我不要犯错误,但我想知道 C++ 类型特征是否有办法限制它们的输入类型,以便它们不接受其他 type_traits 作为参数。现在困难的是在 type_traits 中有大量类型特征,所以 IDK 如何最好地实现它。

注意:我不是说 C++ 应该这样做,我知道防止罕见错误需要做很多工作,我只是想了解更复杂的概念设计,其中您的限制不是基于类型的语义(也就是 ++和 *) 但事实上类型属于大量类型(并且该集合包括您限制的类型)。

标签: c++typetraitsc++20c++-concepts

解决方案


好吧,假设您在可能的情况下总是需要::typeas 参数,这里有一个快速的解决方法:

template<class T> concept HasType = requires { typename T::type; };
template<class T> concept HasNoType = !HasType<T>;

template<HasNoType T> using remove_cv = std::remove_cv<T>;
template<HasNoType T> using remove_cv_t = typename remove_cv<T>::type;

除了修补 STL 标头或子类化 STL 类型(并非总是允许)之外,您无法重新定义预定义的内容。

您的限制不是基于类型的语义(又名具有 ++ 和 *),而是基于类型属于大量类型的事实

无论发生什么,您都需要一个谓词来指定这个集合(∊S给定 S 的运算符)。例如has ++,与其他任何谓词一样好。

谓词可以用更多级别的间接和一些样板来细化,比如说

template<class T> struct not_a_type_trait =
        std::integral_constant<bool, HasNoType<T>> {};
template<class T> inline constexpr not_a_type_trait_v = not_a_type_trait<T>::value;
template<class T> concept NotATrait = not_a_type_trait_v<T>;

struct AnArg { using type = void; };
template<> struct not_a_type_trait<AnArg>: std::true_type {};
    // now can be an arg to remove_cv

或者,在这种特殊情况下,您可以简单地将所有 STL 的特征列入黑名单,但这将是一个非常大的谓词,需要随着每个标准版本的更新而更新。


推荐阅读