如何使用类型特征和概念检测指向算术类型的指针?

How to detect a pointer to an arithmetic type using type traits and concepts?

如何编写检测算术类型指针的概念?

template <typename T>
concept arithmetic = std::is_arithmetic<T>::value;

template <typename T>
concept pointer_to_arithmetic = requires (T a) {
    { *a } -> arithmetic;
};

template <typename T>
void fn() {
    printf("fail\n");
}   

template <pointer_to_arithmetic T>
void fn() {
    printf("pass\n");
}   

struct s{};

int main() {
    fn<int>();
    fn<int*>();
    fn<s>();
    fn<s*>();
}

我尝试了上面的方法,它编译了但没有按预期运行。

预期输出为:

fail
pass
fail
fail

相反,我得到:

fail
fail
fail
fail

如果我将*a替换为a[0]也不起作用。

这应该可以解决问题:

template <typename T>
concept pointer_to_arithmetic = requires (T a) {
    requires std::is_arithmetic_v<std::remove_cvref_t<decltype(*a)>>;
    requires std::is_pointer_v<T>;
};

...

pointer_to_arithmetic<int>          -> false
pointer_to_arithmetic<float>        -> false
pointer_to_arithmetic<std::string*> -> false
pointer_to_arithmetic<int*>         -> true
pointer_to_arithmetic<float*>       -> true

第一行检测可以取消引用为算术类型的任何类型。这可能不是你需要的。所以你需要添加第二行来检测 T 是否确实是指针类型。

对于复合需求中的表达式 E,类型约束谓词被馈送 decltype((E))1.

decltype 将表达式的值类别编码为它推导的类型。因为 *p 是一个左值表达式。对于某些 T.

,推导的类型是 T&

因此您可能希望将您的一对概念重写为

template <typename T>
concept arithmetic_ref = std::is_arithmetic<std::remove_reference_t<T>>::value;

template <typename T>
concept pointer_to_arithmetic = requires (T a) {
    { *a } -> arithmetic_ref ;
};

原子谓词可能可以更好地命名。


当然,这留下了几个悬而未决的问题。你只是鸭子打字,所以任何类似指针的类型(甚至 std::optionaloperator*)都是允许的吗?还是您只追求基本的指针类型?该概念应如何处理 cv 限定类型(目前不允许使用它们)?

根据你如何回答这些问题,这个概念可以进一步调整。

您的 arithmetic 特征的类型是 int&s&,而不是 ints。解决此问题的一种方法是从 *a 表达式中删除引用:

template<typename T>
auto decay(T&& t) -> std::remove_cvref_t<T> {
    return t;
}

template <typename T>
concept pointer_to_arithmetic = requires (T a) {
    { decay(*a) } -> arithmetic;
};

解决此问题的另一种方法是让 arithmetic 将对算术类型的引用识别为算术,因为您仍然可以 使用 以相同方式使用变量。这在另一个答案中有所介绍,尽管对概念名称进行了更改。