C++ 中字符类型的类型特征?

问题描述 投票:0回答:2

我正在编写一个能够处理任何整数类型的库函数,但我想阻止它也处理字符类型(例如

char
char16_t
等),因为它可能会让用户感到困惑(我有一个单独的函数来处理看起来像字符的字符)。

我目前正在使用这样的代码:

template <
    typename = std::enable_if_t<
        std::is_integral_v<T> && !std::is_same_v<std::decay_t<T>, bool> &&
        !std::is_same_v<std::decay_t<T>, char> && !std::is_same_v<std::decay_t<T>, wchar_t> &&
        !std::is_same_v<std::decay_t<T>, char16_t> && !std::is_same_v<std::decay_t<T>, char32_t>>>
constexpr auto do_stuff(T curr) noexcept {
    /* TODO */
}

但是,这看起来非常脆弱 - 例如,这在带有

char8_t
的 C++20 编译器上并不完全正确,即使我对
char8_t
进行了正确的功能测试,仍然相当尴尬必须列出他们都出去了。

有没有一种方法可以检测类似字符的类型,而我不需要将它们全部列出来?

c++ char c++20 type-traits
2个回答
1
投票

你可以这样做:

template <
    typename T,
    std::enable_if_t<std::is_integral_v<T>, std::nullptr_t> = nullptr,
    std::enable_if_t<std::is_same_v<T, std::make_signed_t<T>> || std::is_same_v<T, std::make_unsigned_t<T>>, std::nullptr_t> = nullptr
>

这接受

signed char
unsigned char
,同时拒绝
char
int8_t
是所有常见标准库实现(libstdc++、libc++ 和 MSVC 的实现)上的
signed char

注意不寻常的双 SFINAE。这是必要的,因为如果给定非整数类型,

std::make_[un]signed
会导致硬错误。


或者,在 C++20 中,您可以检查

std::cmp_equal
是否接受您的类型。它还拒绝
char
char*_t
,同时允许
[un]signed char

requires requires{ std::cmp_equal(T{}, T{}); }

0
投票

与之前的答案类似,但具有与 C++11 兼容的类型特征:

#include <type_traits>

template<class T>
using is_actually_arithmetic = typename std::conditional<
    std::is_arithmetic<T>::value,
    std::is_same<
        T,
        typename std::conditional<
            std::is_integral<T>::value,
            typename std::conditional<
                std::is_signed<T>::value,
                std::make_signed<T>,
                std::make_unsigned<T>
            >::type,
            std::enable_if<true, std::enable_if<true, T> >
        >::type::type::type
    >,
    std::false_type
>::type;

template<class T>
using is_actually_integral = typename std::conditional<
    std::is_integral<T>::value,
    is_actually_arithmetic<T>,
    std::false_type
>::type;
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.