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)
这该怎么做?
当参数类型不能作为变量参数传递时,产生静态断言的特征的加值点.
#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_t和char16_t char32_t代码重复的问题。
| 归档时间: |
|
| 查看次数: |
586 次 |
| 最近记录: |