gpt4 book ai didi

c++ - 接受用户定义文字的排列时防止过载爆炸

转载 作者:太空狗 更新时间:2023-10-29 20:02:05 26 4
gpt4 key购买 nike

我有一个结构 Dimensions,它具有宽度和高度的模板化参数:

template<unsigned W, unsigned H>
struct Dimensions
{
static constexpr unsigned width = W;
static constexpr unsigned height = H;
};

我有 WidthHeight 类,它们具有各自值的模板化参数:

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_unsignedparse 将字符转换为无符号值

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");
}

因此,我现在可以创建一个函数模板,它采用从字符串文字创建的 WidthHeight 实例,并返回一个 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>{};
}

如果我现在添加第三个维度,Breadthdimensions 重载的数量将会激增,因为它们是我目前实现的方式,它需要一个重载用于每个​​可能的排列.

问题:

有没有办法允许用户使用宽度、宽度和高度的任意组合/顺序来指定尺寸、省略某些尺寸等?

(上述代码在 coliru here 上的工作示例)

最佳答案

最直接的方法是从元函数开始搜索特定维度:

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>();
}

一个更聪明的方法可能是利用继承:

template <template <unsigned> class Z, unsigned N>
constexpr unsigned get_dim(Z<N> d) { return N; }

template <template <unsigned> class Z>
constexpr unsigned get_dim(... ) { return 0; }

template<class... DimensionTs>
auto dimensions(DimensionTs...)
{
struct X : DimensionTs... { };
static constexpr X x {};

return Dimensions<
get_dim<Width>(x),
get_dim<Height(x),
get_dim<Breadth>(x)
>();
}

第二个的优点是重复维度是一个编译错误。

关于c++ - 接受用户定义文字的排列时防止过载爆炸,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46982251/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com