有没有类似模板化案例陈述的东西
Is There Anything Like a Templatized Case-Statement
所以我有这个非常难看的代码:
template <typename T>
std::conditional_t<sizeof(T) == sizeof(char),
char,
conditional_t<sizeof(T) == sizeof(short),
short,
conditional_t<sizeof(T) == sizeof(long),
long,
enable_if_t<sizeof(T) == sizeof(long long),
long long>>>> foo(T bar){return reinterpret_cast<decltype(foo(bar))>(bar);}
我正在使用嵌套的 conditional_t
s 来制作各种案例陈述。有什么东西可以更优雅地实现这一点,还是我需要编写自己的模板化案例语句?
注意:我实际上知道 reinterpret_cast
的这种用法是不好的:
也许是这样的:
template <size_t N> struct SuitablySized;
template<> struct SuitablySized<sizeof(char)> {
typedef char type;
};
template<> struct SuitablySized<sizeof(short)> {
typedef short type;
};
// Add more cases to taste
template <typename T>
typename SuitablySized<sizeof(T)>::type foo(T bar);
switch 语句的模板版本是专门的模板。
template<size_t n> struct matching_type;
template<> struct matching_type<sizeof(char)> { typedef char type; };
template<> struct matching_type<sizeof(short)> { typedef short type; };
template<> struct matching_type<sizeof(int)> { typedef int type; };
template<> struct matching_type<sizeof(long)> { typedef long type; };
template<> struct matching_type<sizeof(long long)> { typedef long long type; };
template<typename T>
matching_type<sizeof(T)>::type foo(T bar)
{
return reinterpret_cast<decltype(foo(bar))>(bar);
}
我不得不做一次这样的事情所以我写了一个small wrapper to acheive the result neatly. You could use it as follows (see here来测试)
template<class T>
typename static_switch<sizeof(T)
,int // default case
,static_case<sizeof(char),char>
,static_case<sizeof(short),short>
,static_case<sizeof(long),long>
>::type foo(T bar){ ... }
在幕后,它几乎完成了您已经拥有的功能,但通过包装它,我们使其(更具)可读性。如果需要,还有一个版本允许您直接切换 T
类型。
编辑:@Deduplicator 的建议是它背后的代码
#include <type_traits>
/*
* Select a type based on the value of a compile-time constant such as a
* constexpr or #define using static_switch.
*/
template<int I,class T>
struct static_case {
static constexpr int value = I;
using type = T;
};
template<int I, class DefaultType, class Case1, class... OtherCases>
struct static_switch{
using type = typename std::conditional< I==Case1::value ,
typename Case1::type,
typename static_switch<I,DefaultType,OtherCases...>::type
>::type;
};
struct fail_on_default {};
template<int I, class DefaultType, class LastCase>
struct static_switch<I,DefaultType,LastCase> {
using type = typename std::conditional< I==LastCase::value ,
typename LastCase::type,
DefaultType
>::type;
static_assert(!(std::is_same<type, fail_on_default>::value),
"Default case reached in static_switch!");
};
只要您了解相同尺寸的类型可能不是敞篷车的风险,您可以简单地插入一个 mpl::map
..
typedef map<
pair<int_<sizeof(char)>, char>,
pair<int_<sizeof(short)>, short>,
pair<int_<sizeof(int)>, int>,
pair<int_<sizeof(long long)>, long long>
> m;
例如
#include <algorithm>
#include <iostream>
#include <boost/mpl/at.hpp>
#include <boost/mpl/map.hpp>
using namespace boost::mpl;
typedef map<
pair<int_<sizeof(char)>, char>,
pair<int_<sizeof(short)>, short>,
pair<int_<sizeof(int)>, int>,
pair<int_<sizeof(long long)>, long long>
> m;
template <typename T>
typename at<m, int_<sizeof(T)>>::type foo(T bar)
{ return reinterpret_cast<decltype(foo(bar))>(bar); }
struct doh
{
std::string a, b, c;
};
int main()
{
{
char c;
static_assert(std::is_same<decltype(foo(c)), char>::value, "error");
}
{
short c;
static_assert(std::is_same<decltype(foo(c)), short>::value, "error");
}
{
int c;
static_assert(std::is_same<decltype(foo(c)), int>::value, "error");
}
{
long long c;
static_assert(std::is_same<decltype(foo(c)), long long>::value, "error");
}
{
double c;
static_assert(std::is_same<decltype(foo(c)), long long>::value, "error");
}
{
doh c;
static_assert(std::is_same<decltype(foo(c)), void_>::value, "error");
}
}
类型标签:
template<class T>struct tag{using type=T;};
void_t
(在 C++17 中出现在您附近的编译器中):
template<class...>struct voider{using type=void;};
template<class...Ts>using void_t=typename voider<Ts...>::type;
enable_first_t
拿了一包std::enable_if
(注意缺少_t
),returns第一个通过测试。您可以使用 tag<X>
替换 std::enable_if<true, X>
:
template<class T,class=void>struct has_type:std::false_type{};
template<class T>struct has_type<T, void_t<typename T::type>>:std::true_type{};
namespace details {
template<class, class...Ts>
struct enable_first {};
template<class T0, class...Ts>
struct enable_first<std::enable_if_t< !has_type<T0>{} >, T0, Ts... >:enable_first<void, Ts...> {};
template<class T0, class...Ts>
struct enable_first<std::enable_if_t< has_type<T0>{} >, T0, Ts...>:T0 {};
}
template<class...Ts>using enable_first_t=typename details::enable_first<void, Ts...>::type;
template<class T>
using result = enable_first_t<
std::enable_if<sizeof(T)==sizeof(char), char>,
std::enable_if<sizeof(T)==sizeof(short), short>,
std::enable_if<sizeof(T)==sizeof(long), long>,
tag<int> // default
>;
这很像 switch
,但语句是完整的布尔表达式。
所以我有这个非常难看的代码:
template <typename T>
std::conditional_t<sizeof(T) == sizeof(char),
char,
conditional_t<sizeof(T) == sizeof(short),
short,
conditional_t<sizeof(T) == sizeof(long),
long,
enable_if_t<sizeof(T) == sizeof(long long),
long long>>>> foo(T bar){return reinterpret_cast<decltype(foo(bar))>(bar);}
我正在使用嵌套的 conditional_t
s 来制作各种案例陈述。有什么东西可以更优雅地实现这一点,还是我需要编写自己的模板化案例语句?
注意:我实际上知道 reinterpret_cast
的这种用法是不好的:
也许是这样的:
template <size_t N> struct SuitablySized;
template<> struct SuitablySized<sizeof(char)> {
typedef char type;
};
template<> struct SuitablySized<sizeof(short)> {
typedef short type;
};
// Add more cases to taste
template <typename T>
typename SuitablySized<sizeof(T)>::type foo(T bar);
switch 语句的模板版本是专门的模板。
template<size_t n> struct matching_type;
template<> struct matching_type<sizeof(char)> { typedef char type; };
template<> struct matching_type<sizeof(short)> { typedef short type; };
template<> struct matching_type<sizeof(int)> { typedef int type; };
template<> struct matching_type<sizeof(long)> { typedef long type; };
template<> struct matching_type<sizeof(long long)> { typedef long long type; };
template<typename T>
matching_type<sizeof(T)>::type foo(T bar)
{
return reinterpret_cast<decltype(foo(bar))>(bar);
}
我不得不做一次这样的事情所以我写了一个small wrapper to acheive the result neatly. You could use it as follows (see here来测试)
template<class T>
typename static_switch<sizeof(T)
,int // default case
,static_case<sizeof(char),char>
,static_case<sizeof(short),short>
,static_case<sizeof(long),long>
>::type foo(T bar){ ... }
在幕后,它几乎完成了您已经拥有的功能,但通过包装它,我们使其(更具)可读性。如果需要,还有一个版本允许您直接切换 T
类型。
编辑:@Deduplicator 的建议是它背后的代码
#include <type_traits>
/*
* Select a type based on the value of a compile-time constant such as a
* constexpr or #define using static_switch.
*/
template<int I,class T>
struct static_case {
static constexpr int value = I;
using type = T;
};
template<int I, class DefaultType, class Case1, class... OtherCases>
struct static_switch{
using type = typename std::conditional< I==Case1::value ,
typename Case1::type,
typename static_switch<I,DefaultType,OtherCases...>::type
>::type;
};
struct fail_on_default {};
template<int I, class DefaultType, class LastCase>
struct static_switch<I,DefaultType,LastCase> {
using type = typename std::conditional< I==LastCase::value ,
typename LastCase::type,
DefaultType
>::type;
static_assert(!(std::is_same<type, fail_on_default>::value),
"Default case reached in static_switch!");
};
只要您了解相同尺寸的类型可能不是敞篷车的风险,您可以简单地插入一个 mpl::map
..
typedef map<
pair<int_<sizeof(char)>, char>,
pair<int_<sizeof(short)>, short>,
pair<int_<sizeof(int)>, int>,
pair<int_<sizeof(long long)>, long long>
> m;
例如
#include <algorithm>
#include <iostream>
#include <boost/mpl/at.hpp>
#include <boost/mpl/map.hpp>
using namespace boost::mpl;
typedef map<
pair<int_<sizeof(char)>, char>,
pair<int_<sizeof(short)>, short>,
pair<int_<sizeof(int)>, int>,
pair<int_<sizeof(long long)>, long long>
> m;
template <typename T>
typename at<m, int_<sizeof(T)>>::type foo(T bar)
{ return reinterpret_cast<decltype(foo(bar))>(bar); }
struct doh
{
std::string a, b, c;
};
int main()
{
{
char c;
static_assert(std::is_same<decltype(foo(c)), char>::value, "error");
}
{
short c;
static_assert(std::is_same<decltype(foo(c)), short>::value, "error");
}
{
int c;
static_assert(std::is_same<decltype(foo(c)), int>::value, "error");
}
{
long long c;
static_assert(std::is_same<decltype(foo(c)), long long>::value, "error");
}
{
double c;
static_assert(std::is_same<decltype(foo(c)), long long>::value, "error");
}
{
doh c;
static_assert(std::is_same<decltype(foo(c)), void_>::value, "error");
}
}
类型标签:
template<class T>struct tag{using type=T;};
void_t
(在 C++17 中出现在您附近的编译器中):
template<class...>struct voider{using type=void;};
template<class...Ts>using void_t=typename voider<Ts...>::type;
enable_first_t
拿了一包std::enable_if
(注意缺少_t
),returns第一个通过测试。您可以使用 tag<X>
替换 std::enable_if<true, X>
:
template<class T,class=void>struct has_type:std::false_type{};
template<class T>struct has_type<T, void_t<typename T::type>>:std::true_type{};
namespace details {
template<class, class...Ts>
struct enable_first {};
template<class T0, class...Ts>
struct enable_first<std::enable_if_t< !has_type<T0>{} >, T0, Ts... >:enable_first<void, Ts...> {};
template<class T0, class...Ts>
struct enable_first<std::enable_if_t< has_type<T0>{} >, T0, Ts...>:T0 {};
}
template<class...Ts>using enable_first_t=typename details::enable_first<void, Ts...>::type;
template<class T>
using result = enable_first_t<
std::enable_if<sizeof(T)==sizeof(char), char>,
std::enable_if<sizeof(T)==sizeof(short), short>,
std::enable_if<sizeof(T)==sizeof(long), long>,
tag<int> // default
>;
这很像 switch
,但语句是完整的布尔表达式。