键入trait以获取默认参数升级 [英] Type trait to obtain default argument promotions

查看:142
本文介绍了键入trait以获取默认参数升级的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

[免责声明:我知道这个问题的答案。 ]

[Disclaimer: I know an answer to this question. I thought it might be of some general interest.]

问题:我们如何能够得到一个类型trait, 默认参数促销

Question: How can we have a type trait that produces the type that results from performing default argument promotions?

动机:我想能够可移植地使用变量参数。例如:

Motivation: I would like to be able to use variable arguments portably. For example:

void foo(char const * fmt, ...);  // Please pass: * unsigned short
                                  //              * bool
                                  //              * char32_t
                                  //              * unsigned char

当向没有参数的函数调用传递参数(即匹配省略号)时,参数会经历默认的参数提升。到目前为止这么好,但那些促销是平台依赖。我可以用 va_arg(ap,T)来恢复参数,但是 T

When passing arguments to a function call without parameters, i.e. matching the ellipsis, the arguments undergo default argument promotion. So far so good, but those promotions are platform dependent. I can recover the arguments with va_arg(ap, T), but what is T?

现在,对于一些简单的情况,这很容易:例如,我可以总是说:

Now, for some simple situations this is easy: For example, I can always say:

unsigned short n = va_args(ap, unsigned int);

默认促销将导致 signed int unsigned int ,但根据说,C11 7.16.1.1/3,va-casting到 unsigned int 总是很好,因为即使默认促销导致 int ,原始值也可以由两种类型表示。

The default promotion will result in either a signed int or an unsigned int, but according to, say, C11 7.16.1.1/3, va-casting to unsigned int is always fine, since even if the default promotion results in an int, the original value can be represented by both types.

但是,当我期望一个 char32_t 时,我应该使用什么类型? C ++ 11 4.5 / 2将生成的类型打开。所以我想要一个trait让我写:

But what type should I cast to when I expect a char32_t? C++11 4.5/2 leaves the resulting type wide open. So I would like a trait that lets me write:

char32_t c = va_args(ap, default_promote<char32_t>::type);

如何做?

奖金

推荐答案

这里是一个骨架一个适用于大多数类型(整数,浮点,无范围枚举,数组,指针,指向成员,函数,函数指针)的解决方案。

Here's a skeleton of a solution that works for "most" types (integral, float, unscoped enumeration, arrays, pointers, pointers-to-member, functions, function pointers).

#include <type_traits>

template <typename U>
struct default_promote
{
    // Support trait for scoped enums

    template <typename E, bool IsEnum>
    struct is_unscoped_enum : std::false_type { };

    template <typename E> struct is_unscoped_enum<E, true>
    : std::is_convertible<E, typename std::underlying_type<E>::type> { };


    // Floating point promotion

    static double test(float);


    // Integral promotions (includes pointers, arrays and functions)

    template <typename T, typename = typename std::enable_if<!is_unscoped_enum<T, std::is_enum<T>::value>::value>::type>
    static auto test(T) -> decltype(+ std::declval<T>());

    template <typename T, typename = typename std::enable_if<is_unscoped_enum<T, std::is_enum<T>::value>::value>::type>
    static auto test(T) -> decltype(+ std::declval<typename std::underlying_type<T>::type>());


    // Pointers-to-member (no promotion)

    template <typename T, typename S>
    static auto test(S T::*) -> S T::*;


    using type = decltype(test(std::declval<U>()));
};

它不提供无法安全地通过省略号的类型的诊断。此外,此解决方案包含类型作为可变函数参数传递时所经历的衰减,因此它不仅仅是关于促销的。

It does not provide diagnostics for types that cannot safely be passed through an ellipsis. Also, this solution subsumes the decay that types undergo when passed as variable function arguments, so it is not strictly about promotion only.

它通过明确处理指针 - 成员类型和浮点转换,并依赖于一元运算符 + 用于积分和无范围的枚举类型;例如C ++ 11 5.3.1 / 7:

It works by handling explicitly the pointer-to-member types and the floating point conversion, and by relying on the unary operator + for integral and unscoped enumeration types; e.g. C++11 5.3.1/7:


一元的操作数 + 运算符应具有算术,无作用域的枚举或指针类型,结果是参数的值。对积分或枚举操作数执行积分提升。

The operand of the unary + operator shall have arithmetic, unscoped enumeration, or pointer type and the result is the value of the argument. Integral promotion is performed on integral or enumeration operands. The type of the result is the type of the promoted operand.

需要一些额外的工作来处理枚举,因为它可以用于枚举的超载运算符(范围和未范围),因此必须小心使用朴素一元加运算符。也就是说,当枚举无范围时,我们必须考虑促进底层类型,并且完全禁止范围内的枚举。

Some extra work is needed to handle enumerations, since it is possible to overload operators for enumerations (both scoped and unscoped), and so the naive unary plus operator must be used with care. That is, we must consider the promotion of the underlying type when the enum is unscoped, and forbid scoped enums entirely.

这篇关于键入trait以获取默认参数升级的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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