我有一个结构Dimensions
,它有宽度和高度的模板化参数:
template<unsigned W, unsigned H>
struct Dimensions
{
static constexpr unsigned width = W;
static constexpr unsigned height = H;
};
我有Width
和Height
个类,它们的各自值都有模板化参数:
template<unsigned N>
struct Width
{
static constexpr unsigned value = N;
};
template<unsigned N>
struct Height
{
static constexpr unsigned value = N;
};
我为宽度和高度创建了用户定义的文字
template<char... cs>
constexpr auto operator""_w() -> Width<to_unsigned(0, parse(cs)...)>
{
return {};
}
template<char... cs>
constexpr auto operator""_h() -> Height<to_unsigned(0, parse(cs)...)>
{
return {};
}
其中to_unsigned
和parse
将字符转换为无符号值
constexpr unsigned to_unsigned(unsigned p)
{
return p;
}
template<class... Ts>
constexpr unsigned to_unsigned(unsigned val, unsigned v, Ts... vs)
{
return to_unsigned(val * 10 + v, vs...);
}
constexpr unsigned parse(char C)
{
return (C >= '0' && C <= '9')
? C - '0'
: throw std::out_of_range("input is not a number");
}
因此,我现在可以创建一个函数模板,该模板采用从字符串文字创建的Width
和Height
个实例,并返回Dimensions
template<unsigned W, unsigned H>
constexpr Dimensions<W, H> dimensions(Width<W>, Height<H>)
{
return Dimensions<W, H>{};
}
auto d = dimensions(5_w, 10_h);
static_assert(d.width == 5, "");
static_assert(d.height == 10, "");
我想让用户只能提供一个维度(另一个维度为0),或者以不同的顺序提供文字。
我目前实现的方法是有许多不同的重载:
// width, height
template<unsigned W, unsigned H = 0>
constexpr Dimensions<W, H> dimensions(Width<W>, Height<H>)
{
return Dimensions<W, H>{};
}
// height, width
template<unsigned H, unsigned W = 0>
constexpr Dimensions<W, H> dimensions(Height<H>, Width<W>)
{
return Dimensions<W, H>{};
}
如果我现在添加第三个维度Breadth
,dimensions
重载的数量将会爆炸,因为我目前已经实现了它,每次可能的排列都需要一次重载。
问题:
有没有办法允许用户使用宽度,宽度和高度的任意组合/排序来指定尺寸,省略一些等等?
(关于coliru here的上述代码的工作示例)
答案 0 :(得分:8)
最直接的方法是从元函数开始搜索特定维度:
SELECT
COUNT(`user_id`) > 0
FROM
`user`
GROUP BY
`user_id`
HAVING
SUM(CASE WHEN `user`.`email`="admin@admin.com" THEN 1 ELSE 0 END) <> 0 AND
SUM(CASE WHEN `user`.`user_id`=1 THEN 1 ELSE 0 END) <> 0
然后我们就用它了:
template <template <unsigned> class Z, class... Ts>
struct find_dimension;
template <template <unsigned> class Z, class... Ts>
using find_dimension_t = typename find_dimension<Z, Ts...>::type;
// found it
template <template <unsigned> class Z, unsigned N, class... Ts>
struct find_dimension<Z, Z<N>, Ts...> {
using type = Z<N>;
};
// keep going
template <template <unsigned> class Z, class T, class... Ts>
struct find_dimension<Z, T, Ts...>
: find_dimension<Z, Ts...>
{ };
// default to 0
template <template <unsigned> class Z>
struct find_dimension<Z> {
using type = Z<0>;
};
更聪明的方法可能是利用继承:
template <class... Dimensions>
auto dimensions(Dimensions... ) {
using height = find_dimension_t<Height, Dimensions...>;
using width = find_dimension_t<Width, Dimensions...>;
using breadth = find_dimension_t<Breadth, Dimensions...>;
return Dimensions<width::value, height::value, breadth::value>();
}
第二个很好的特性是重复的维度是一个编译错误。