输入trait以获取默认参数促销

Ker*_* SB 8 c++ variadic-functions type-traits

[免责声明:我知道这个问题的答案.我认为这可能有一些普遍的兴趣.]

问题:我们怎样才能有一个类型特征产生由执行默认参数促销产生的类型?

动机:我希望能够可移植地使用变量参数.例如:

void foo(char const * fmt, ...);  // Please pass: * unsigned short
                                  //              * bool
                                  //              * char32_t
                                  //              * unsigned char
Run Code Online (Sandbox Code Playgroud)

当将参数传递给没有参数的函数调用时,即匹配省略号时,参数会进行默认参数提升.到目前为止一直很好,但这些促销是依赖于平台的.我可以恢复参数va_arg(ap, T),但是什么T

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

unsigned short n = va_args(ap, unsigned int);
Run Code Online (Sandbox Code Playgroud)

默认促销将导致a signed int或an unsigned int,但根据,例如,C11 7.16.1.1/3,va-casting unsigned int总是很好,因为即使默认促销结果为a int,原始值也可以由两者表示类型.

但是当我期待一个类型时,我应该选择什么类型char32_t?C++ 11 4.5/2使得结果类型大开.所以我想要一个让我写的特质:

char32_t c = va_args(ap, default_promote<char32_t>::type);
Run Code Online (Sandbox Code Playgroud)

这该怎么做?

当参数类型不能作为变量参数传递时,产生静态断言的特征的加值点.

Sca*_*nth 2

#include <cstdlib>
#include <stdarg.h>
#include <type_traits>

// Utility type if / else
template <typename T, typename U, bool choose>
struct TifChooseU { };

template <typename T, typename U>
struct TifChooseU <T, U, true> {
    using type = T;
};

template <typename T, typename U>
struct TifChooseU <T, U, false> {
    using type = U;
};

// Default - No Promotion
template <typename T>
struct promote_me {
    using type = T;
};

// http://en.cppreference.com/w/cpp/language/implicit_cast - Let's go in order
// Signed char - int
template <>
struct promote_me <signed char> {
    using type = int;
};

// Signed short - int
template <>
struct promote_me <signed short> {
    using type = int;
};

// Unsigned char - int or unsigned int, dependent on inter-stellar configuration
template <>
struct promote_me <unsigned char> {
    // Doesn't compile without the parens around the operator >
    using type = TifChooseU <int, unsigned int, (sizeof(int) > sizeof(unsigned char))>::type;
};

// Unsigned short - int or unsigned int, dependent on inter-stellar configuration
template <>
struct promote_me <unsigned short> {
    // Doesn't compile without the parens around the operator >
    using type = TifChooseU <int, unsigned int, (sizeof(int) > sizeof(short))>::type;
};

// Char - dispatch to unsigned / signed char
template <>
struct promote_me <char> :
       promote_me <TifChooseU <signed char, unsigned char,
                               std::is_signed<char>::value>::type> {};

// Wchar_t - int, unsigned int, long, unsigned long, long long, unsigned long long
// dependent on the amount of goats recently sacrificed
template <>
struct promote_me <wchar_t> {
    using type =
        TifChooseU <
        TifChooseU <int,
            TifChooseU<long, long long, (sizeof(long) > sizeof(wchar_t))>::type,
            (sizeof(int) > sizeof(wchar_t))>::type,
        TifChooseU <unsigned int,
            TifChooseU<unsigned long, unsigned long long, (sizeof(unsigned long) > sizeof(wchar_t))>::type,
            (sizeof(int) > sizeof(wchar_t))>::type,
        std::is_signed<wchar_t>::value
    >::type;
};

// Char16_t - int, unsigned int, long, unsigned long, long long, unsigned long long
// dependent on the amount of goats recently sacrificed
template <>
struct promote_me <char16_t> {
    using type =
        TifChooseU <
        TifChooseU <int,
            TifChooseU<long, long long, (sizeof(long) > sizeof(char16_t))>::type,
            (sizeof(int) > sizeof(char16_t))>::type,
        TifChooseU <unsigned int,
            TifChooseU<unsigned long, unsigned long long, (sizeof(unsigned long) > sizeof(char16_t))>::type,
            (sizeof(int) > sizeof(char16_t))>::type,
        std::is_signed<char16_t>::value
    >::type;
};

// Char32_t - int, unsigned int, long, unsigned long, long long, unsigned long long
// dependent on the amount of goats recently sacrificed
template <>
struct promote_me <char32_t> {
    using type =
        TifChooseU <
        TifChooseU <int,
            TifChooseU<long, long long, (sizeof(long) > sizeof(char32_t))>::type,
            (sizeof(int) > sizeof(char32_t))>::type,
        TifChooseU <unsigned int,
            TifChooseU<unsigned long, unsigned long long, (sizeof(unsigned long) > sizeof(char32_t))>::type,
            (sizeof(int) > sizeof(char32_t))>::type,
        std::is_signed<char32_t>::value
    >::type;
};

// Enums and Bitfields - maybe later ^^

// Bool - int
template <>
struct promote_me <bool> {
    using type = int;
};

void foo(const char* fmt, ...) {
    va_list va;
    va_start(va, fmt);
    unsigned short a = va_arg(va, promote_me<unsigned short>::type);
    bool           b = va_arg(va, promote_me<bool>::type);
    char32_t       c = va_arg(va, promote_me<char32_t>::type);
    unsigned char  d = va_arg(va, promote_me<unsigned char>::type);
}

int main() {

const char* fmt;
unsigned short a = 1;
bool           b = true;
char32_t       c = 'a';
unsigned char  d = 'c';

foo(fmt, a, b, c, d);

}
Run Code Online (Sandbox Code Playgroud)

如果有一个简单的解决方案,我会考虑自杀:)。
我可能会使用fits<T, U>模板来改进这一点,并且我还将修复
不优雅wchar_tchar16_t char32_t代码重复的问题。

  • 好吧,别开枪了,但我认为对于 C++11 来说,有一个类似三行的解决方案(如果你在新行上加上大括号)。 (4认同)
  • 我认为一元 + 与 `decltype` 结合可以用来测试积分提升。 (2认同)
  • @ScarletAmaranth:任何数学表达式都会导致升级发生,而 `+var` 是一个表达式...... (2认同)