5

我有一个只能为标量类型(整数、浮点数等)实例化的模板类,我希望成员 typedef 始终是该类型的有符号变体。那是:

unsigned int-> signed int
signed long long-> signed long long(已经签名)
unsigned char-> signed char
float-> float
long double->long double
等等...

不幸的是,std::make_signed仅适用于整数类型,不适用于浮点类型。最简单的方法是什么?我正在寻找某种形式的东西,using SignedT = ...;成为我的模板化类的一部分,模板参数 T 已经保证是标量。

4

4 回答 4

11

一个简单的模板别名就可以了:

#include <type_traits>

template<typename T>
struct identity { using type = T; };

template<typename T>
using try_make_signed =
    typename std::conditional<
        std::is_integral<T>::value,
        std::make_signed<T>,
        identity<T>
        >::type;

这就是你如何测试它:

int main()
{
    static_assert(::is_same<
        try_make_signed<unsigned int>::type, int
        >::value, "!");

    static_assert(std::is_same<
        try_make_signed<double>::type, double
        >::value, "!");
}

这是一个活生生的例子

于 2013-05-04T18:53:03.907 回答
3

在我最初尝试使用 有缺陷之后std::conditional,我决定改用 SFINAE。我std::enable_if用来有条件地启用浮点类型的专业化:

template<typename T, typename Enable = void>
struct my_make_signed {
    typedef typename std::make_signed<T>::type type;
};

template<typename T>
struct my_make_signed<T,
    typename std::enable_if<std::is_floating_point<T>::value>::type> {
    typedef T type;
};
于 2013-05-04T18:50:13.920 回答
2

@jrok 最初有可以工作的代码,他只需要做一个小的调整。这是工作代码:

template<typename T>
struct YourClass
{
    using SignedT =
        typename std::conditional
        <
            std::is_floating_point<T>::value, //if floating point type
            std::common_type<T>,              //use it as-is
            std::make_signed<T>               //otherwise make sure it is signed
        >::type::type; //notice the double ::type
};

演示:http: //ideone.com/Vw7o82

如果需要多次使用此功能,也可以将上述结构修改为自身为类型特征类。但是,@Andy Prowl 的回答是使用别名模板,这样更好。

于 2013-05-04T19:32:07.513 回答
0
namespace mine {        

    template<typename T, bool b>
    struct make_signed__ {
        typedef T type;
    };

    template<typename T>
    struct make_signed__<T,false> {
        typedef typename std::make_signed<T>::type type;
    };

    template<typename T>
    struct make_signed {
        typedef typename make_signed__<T, std::is_floating_point<T>::value>::type type;
    };

}

int main () {
    std::cout << std::is_same<mine::make_signed<unsigned int>::type, int>::value;
    std::cout << std::is_same<mine::make_signed<long double>::type, long double>::value;
}
于 2013-05-04T18:54:23.413 回答