利用str_const,我有一个constexpr字符串。
class StrConst
{
public:
template<size_t N>
constexpr StrConst(const char (&str)[N])
: str_(str)
, len_(N - 1)
{
static_assert(N > 1, "not a string");
}
constexpr operator const char*() const
{
return str_;
}
constexpr size_t size() const
{
return len_;
}
constexpr char operator[] (size_t i) const
{
return i < len_ ? str_[i] : throw std::out_of_range("invalid index");
}
private:
const char* const str_;
const size_t len_;
};我有另一个constexpr函数,它返回字符串中第一个插入符号的位置,从位置n开始:
constexpr int caretPos(const StrConst& str, size_t n = 0)
{
if (n == str.size())
return -1;
if (str[n] == '^')
return n;
return caretPos(str, n+1);
}我可以使用caretPos的结果来为std::tuple of std::integral_constants创建typedef,其中元组的大小是字符串中找到的插入符号的数目,每个元组元素都是一个积分常量,其值是字符串中插入符号的位置。
在这里,我手动构建这个元组:
int main()
{
constexpr StrConst s("hello^world^");
constexpr int pos1 = caretPos(s);
constexpr int pos2 = caretPos(s, pos1+1);
using P1 = std::integral_constant<int, pos1>;
using P2 = std::integral_constant<int, pos2>;
using PosTuple = std::tuple<P1, P2>;
static_assert(std::tuple_element_t<0, PosTuple>::value == 5, "");
static_assert(std::tuple_element_t<1, PosTuple>::value == 11, "");
}问题:
现在,我想将其推广到任何具有任意数目插入符的输入字符串。
template<size_t... Ns>
using PosTuple = std::tuple<std::integral_constant<int, Ns>...>;如何使用Ns...或其他方法生成这里所需的caretPos序列?
工作实例
发布于 2017-04-10 13:40:19
有趣的问题。
避免使用StrConst,在下面的示例中,您可以看到一种获取std::tuple<std::integral_constant<std::size_t, Pos1>, std::integral_constant<std::size_t, Pos2>, ...>类型的方法。
首先,使用arrayConverter()在std::array<char, N>中转换char const * (在以下代码中为lc);第二:使用tupleIndexGenerator<lc.size(), lc, '^'>::type获取所请求的类型。
因此,如果"hello^world^"是字符串,则从tupleIndexGenerator<lc.size(), lc, '^'>::type获得std::tuple<std::integral_constant<std::size_t, 5U>, std::integral_constant<std::size_t, 11U>>
密码
#include <iostream>
#include <array>
#include <tuple>
template <typename, typename>
struct typeConcat;
template <typename T0, template <typename ...> class C, typename ... Ts>
struct typeConcat<T0, C<Ts...>>
{ using type = C<T0, Ts...>; };
template <std::size_t N, std::array<char, N> const & A, char CH,
std::size_t Pos = 0U, bool EQ = ((Pos < N) && (A.at(Pos) == CH))>
struct tupleIndexGenerator;
template <std::size_t N, std::array<char, N> const & A, char CH>
struct tupleIndexGenerator<N, A, CH, N, false>
{ using type = std::tuple<>; };
template <std::size_t N, std::array<char, N> const & A, char CH,
std::size_t Pos>
struct tupleIndexGenerator<N, A, CH, Pos, false>
{ using type = typename tupleIndexGenerator<N, A, CH, Pos+1U>::type; };
template <std::size_t N, std::array<char, N> const & A, char CH,
std::size_t Pos>
struct tupleIndexGenerator<N, A, CH, Pos, true>
{ using type = typename typeConcat<
std::integral_constant<std::size_t, Pos>,
typename tupleIndexGenerator<N, A, CH, Pos+1U>::type>::type; };
template <typename T, size_t N, size_t ... Is>
constexpr auto arrayConverter (T const (&arr)[N],
std::index_sequence<Is...> const &)
{ return std::array<T, N> { { arr[Is]... } }; }
template <typename T, size_t N>
constexpr auto arrayConverter (T const (&arr)[N])
{ return arrayConverter(arr, std::make_index_sequence<N>{}); }
constexpr auto lc = arrayConverter("hello^world^");
int main ()
{
static_assert(std::is_same<
typename tupleIndexGenerator<lc.size(), lc, '^'>::type,
std::tuple<std::integral_constant<std::size_t, 5U>,
std::integral_constant<std::size_t, 11U>>>::value,
"!");
}发布于 2017-04-10 01:53:30
下面是使用一个例子的Boost.Hana (广告是C++14)。它的结果是一个元组的积分常数,这是直接要求。
#include <cstddef>
#include <utility>
#include <boost/hana.hpp>
namespace hana = boost::hana;
using namespace boost::hana::literals;
template<typename Str, int... Is>
constexpr auto unfilteredCaretsImpl(Str str, std::integer_sequence<int, Is...>) {
return hana::make_tuple(boost::hana::if_(str[hana::int_c<Is>] == hana::char_c<'^'>, hana::just(hana::int_c<Is>), hana::nothing)...);
}
template<typename Str>
constexpr auto unfilteredCarets(Str str) {
return unfilteredCaretsImpl(str, std::make_integer_sequence<int, hana::length(str)>{});
}
template<typename Str>
constexpr auto allCarets(Str str) {
auto unfiltered = unfilteredCarets(str);
auto filtered = hana::filter(unfiltered, [](auto opt) { return opt != hana::nothing; });
return hana::transform(filtered, [](auto opt) { return opt.value(); });
}
int main() {
constexpr auto carets = allCarets(BOOST_HANA_STRING("hello^world^"));
static_assert(hana::length(carets) == std::size_t{2});
static_assert(carets[0_c] == 5);
static_assert(carets[1_c] == 11);
}大多数工作都是绕过这样一个事实,即每个值都是不同的类型。Hana将值编码为类型的一部分,这意味着可以在常量表达式中使用参数。例如,Hana字符串的类型为String<'a', 'b', 'c'>,用于某些人工String。这意味着当使用参数比较一个字符时,该字符被称为类型的一部分。这与string不同,后者在constexpr上完全可用,不能将参数提升到函数中的常量表达式。
发布于 2017-04-10 01:57:27
下面是带有Scott字符串的我尽我所能:
#include <cstddef>
#include <stdexcept>
class StrConst
{
public:
template<size_t N>
constexpr StrConst(const char (&str)[N])
: str_(str)
, len_(N - 1)
{
static_assert(N > 1, "not a string");
}
constexpr operator const char*() const
{
return str_;
}
constexpr size_t size() const
{
return len_;
}
constexpr char operator[] (size_t i) const
{
return i < len_ ? str_[i] : throw std::out_of_range("invalid index");
}
private:
const char* const str_;
const size_t len_;
};
template<typename T, size_t MaxSize>
class VectorConst
{
public:
constexpr VectorConst() = default;
constexpr size_t size() const
{
return _size;
}
constexpr void push_back(const T& value) {
_data[_size++] = value;
}
constexpr T& operator[](size_t i)
{
return _data[i];
}
constexpr const T& operator[](size_t i) const
{
return _data[i];
}
private:
T _data[MaxSize]{};
size_t _size = 0;
};
template<size_t Size>
constexpr auto allCarets(const StrConst& str) {
VectorConst<size_t, Size> result;
for (size_t i = 0; i < str.size(); ++i) {
if (str[i] == '^') {
result.push_back(i);
}
}
return result;
}
int main() {
constexpr StrConst s("hello^world^");
constexpr auto carets = allCarets<s.size()>(s);
static_assert(carets.size() == 2);
static_assert(carets[0] == 5);
static_assert(carets[1] == 11);
}由于普通的constexpr和值没有在类型中编码,所以我们受到了更多的限制。我们不能形成一个积分常量元组,因为参数中的字符串内容在常量表达式中是不可用的。相反,我做了一个小的constexpr向量,我们可以像使用运行时的向量一样,在找到位置时推送位置,但是即使这样,我们也不能在编译时进行任何动态分配,所以它有一个最大的大小,需要一个模板参数。使用C++11,您也可以递归地编写这个代码,而不是迭代编写,但我不确定如何实现push_back。您需要复制数组并更改值。据我所知,您必须通过数组的初始化程序列表来完成这一任务,并且本质上需要一个参数包,其大小基于一个变量,该变量不是常量表达式,这是可能的(虽然我不知道C++11),但是真的很复杂。
https://stackoverflow.com/questions/43312515
复制相似问题