gpt4 book ai didi

c++ - 可变参数模板 : SFINAE on last argument

转载 作者:行者123 更新时间:2023-12-05 04:33:26 24 4
gpt4 key购买 nike

我有一个数组(任意级别),我想要一个索引运算符:

  1. 允许缺少索引,使得以下等价

    a(1, 0, 0, 0);
    a(1, my::missing);

    这本身就很简单(参见下面的示例实现):一个人只是递归地添加 arg * strides[dim] 直到 my::missing 命中。

  2. 允许自动在前面添加零,使得以下等价

    a(0, 0, 0, 1);
    a(1);

    这也不难(参见下面的示例实现):递归地添加 arg * strides[dim + offset]

我无法理解的是:如何将两者结合起来? 2. 的实现让我从错误的角度开始了 1.(我仅限于 <= C+ +14)

没有自动前置零的“my::missing”的示例实现

enum class my { missing };

template <size_t dim, class S>
inline size_t index_impl(const S&) noexcept
{
return 0;
}

template <size_t dim, class S, class... Args>
inline size_t index_impl(const S& strides, enum my arg, Args... args) noexcept
{
return 0;
}

template <size_t dim, class S, class Arg, class... Args>
inline size_t index_impl(const S& strides, Arg arg, Args... args) noexcept
{
return arg * strides[dim] + index_impl<dim + 1>(strides, args...);
}

template <class S, class Arg, class... Args>
inline size_t index(const S& strides, Arg arg, Args... args)
{
return index_impl<0>(strides, arg, args...);
}

int main()
{
std::vector<size_t> strides = {8, 4, 2 ,1};
std::cout << index(strides, 1, 2, 0, 0) << std::endl;
std::cout << index(strides, 1, 2, my::missing) << std::endl;
}

没有“my::missing”的前置零的示例实现

template <size_t dim, class S>
inline size_t index_impl(const S&) noexcept
{
return 0;
}

template <size_t dim, class S, class Arg, class... Args>
inline size_t index_impl(const S& strides, Arg arg, Args... args) noexcept
{
return arg * strides[dim] + index_impl<dim + 1>(strides, args...);
}

template <class S, class Arg, class... Args>
inline size_t index(const S& strides, Arg arg, Args... args)
{
constexpr size_t nargs = sizeof...(Args) + 1;
if (nargs == strides.size())
{
return index_impl<0>(strides, arg, args...);
}
else if (nargs < strides.size())
{
return index_impl<0>(strides.cend() - nargs, arg, args...);
}
return index_impl<0>(strides, arg, args...);
}

int main()
{
std::vector<size_t> strides = {8, 4, 2 ,1};
std::cout << index(strides, 1, 2) << std::endl;
std::cout << index(strides, 0, 0, 1, 2) << std::endl;
}

最佳答案

在这个答案的早期版本中,我没有提供完整的实现,因为有些事情对我来说没有意义。

如果此 index 应计算扁平化多维数组的索引,则您的示例实现无效。问题是隐藏的,因为您正在将 index 的两个结果与提供的所有索引进行比较,并缩短假定零填充的版本。
遗憾的是,我在 Catch2 的第一版测试中使用了这种模式。

这是对扁平化多维数组索引的正确测试,其中最后一个索引与扁平化索引匹配:

TEST_CASE("index")
{
std::vector<size_t> strides = { 4, 6, 3, 5 };

SECTION("Padding with leading zeros")
{
constexpr auto i0 = 4;
constexpr auto i1 = 2;
constexpr size_t expected = i0 + i1 * 5;

CHECK(index(strides, 0, 0, i1, i0) == expected);
CHECK(index(strides, 0, 0, i1, i0 - 1) == expected - 1); // last index indexes by one
CHECK(index(strides, i1, i0) == expected);
CHECK(index(strides, i1, i0 - 1) == expected - 1);
}

SECTION("Use my::missing to use padding with tailing zeros")
{
constexpr auto i2 = 4;
constexpr auto i3 = 2;
constexpr size_t expected = (i3 * 6 + i2) * 5 * 3;

CHECK(index(strides, i3, i2, 0, 0) == expected);
CHECK(index(strides, i3, i2, my::missing) == expected);
}
}

现在从您的代码开始并通过这些测试我得到了这个实现:

template <typename T, typename... Ts>
struct last_type_helper {
using type = typename last_type_helper<Ts...>::type;
};

template <typename T>
struct last_type_helper<T> {
using type = T;
};

template <typename... Ts>
using last_type = typename last_type_helper<Ts...>::type;

enum class my { missing };
template <typename... Ts>
constexpr bool LastTypeIsMy = std::is_same<my, last_type<Ts...>>::value;

template <class StrideIter>
size_t index_impl(size_t base, StrideIter)
{
return base;
}

template <class StrideIter>
size_t index_impl(size_t base, StrideIter, my)
{
return base;
}

template <class StrideIter, typename Tn, typename... Ts>
size_t index_impl(size_t base, StrideIter it, Tn xn, Ts... x)
{
return index_impl(base * *it + xn, it + 1, x...);
}

template <class S, class... Args>
size_t index(const S& strides, Args... args)
{
const size_t offset = strides.size() - sizeof...(Args);
const size_t advenceBy = LastTypeIsMy<Args...> ? 0 : offset;
const size_t lastStrides = LastTypeIsMy<Args...> ? offset + 1 : 0;
const size_t tailFactor = std::accumulate(std::end(strides) - lastStrides, std::end(strides),
size_t { 1 }, std::multiplies<> {});

return index_impl(0, std::begin(strides) + advenceBy, args...) * tailFactor;
}

这里是 live demo (通过测试)。

关于c++ - 可变参数模板 : SFINAE on last argument,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71423523/

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