我有一种情况,我想对模板参数包中的每个值调用一些函数,并将调用该函数的结果存储在堆栈分配的变量中。例如:

#include <string>
#include <utility>
#include <functional>

char const* format_value(double x) { /* ... */ }
std::string format_value(long x) { /* ... */ }

template <typename Sink, typename... Values>
Sink& format(Sink& target, Values... values)
{
    // Does not compile; Not valid C++11
    typedef std::tuple<typename std::result_of<format_value(values)>::type...> tuple_type;
    tuple_type slices(format_value(values)...);
    /* Code that does things with the results. */
}


可以进行这种过滤吗?如果可以,我该怎么做?

最佳答案

好的。我看到了your code at github,并希望知道您要实现的目标。

我认为您仍然可以避免对format_buffer()的递归调用。这是我正在谈论的部分:

template <typename Slice, typename... Slices>
char const* format_buffer(char* ptr, std::size_t length, Slice const& slice, Slices const& ...slices)
{
    std::size_t const size = slice.size();
    std::copy_n(slice.data(), size, ptr);
    return format_buffer(ptr + size, length - size, slices...);
}

template <typename Sink, typename... Slices>
Sink& write_impl(Sink& target, Slices &&...slices)
{
    std::size_t const length = sum_sizes(slices...);
    OptimisticBuffer<256> buff(length);
    char* ptr = buff.GetAs<char>();
    char const* endPtr = format_buffer(ptr, length, slices...);
    target.append(ptr, endPtr - ptr);
    return target;
}


可以替换为:

struct unpack { template<typename ...T> unpack(T && ...) {} };

template <typename Sink, typename... Slices>
Sink& write_impl(Sink& target, Slices &&...slices)
{
    std::size_t const length = sum_sizes(slices...);
    OptimisticBuffer<256> buff(length);
    char* ptr = buff.GetAs<char>();
    char *origin = ptr;
    unpack { (ptr = std::copy_n(slices.data(), slices.size(), ptr)) ... } ;
    target.append(origin, ptr - origin);
    return target;
}


魔术发生在unpack {}行。对于slice中的每个slices,您调用std::copy_n并返回ptr+size(然后将其存储在ptr中),该输入成为下一次对std::copy_n的调用的输入,依此类推:

 unpack { (ptr = std::copy_n(slices.data(), slices.size(), ptr)) ... } ;


扩展为:

 unpack
 {
     (ptr = std::copy_n(slices0.data(), slices0.size(), ptr)),
     (ptr = std::copy_n(slices1.data(), slices1.size(), ptr)),
     (ptr = std::copy_n(slices2.data(), slices2.size(), ptr)),
      .
      .
     (ptr = std::copy_n(slicesN.data(), slicesN.size(), ptr)),
 };


请注意,由于它使用列表初始化,因此可以确保表达式的求值顺序是从左到右,即以扩展形式从上到下!

由于GCC has bug since 4.7.0(这就是当前它不起作用的原因),您可以这样编写:

using unpack = void const*[];

unpack {(ptr=std::copy_n(slicesN.data(),slicesN.size(), ptr))...};`


另一个改进是:我将实现sum_sizes()而不是sum,而不是这样:

 std::size_t const length = sum_sizes(slices...);


我可以这样写:

 std::size_t const length = sum(slices.size()...);


这样,sum()将更可重用,例如:

 std::size_t const x = sum(args.get_element_size()...);
 std::size_t const y = sum(sizeof(Ts)...);


如果您需要这些。好吧,在sizeof的情况下,编译时sum<>会更好-尽管要点仍然相同,但sumsum_sizes()更可重用。

关于c++ - 是否可以从模板参数包构建“过滤的元组”或“过滤的参数包”?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20439495/

10-11 03:34
查看更多