我有一种情况,我想在模板参数包中的每个值上调用一些函数,并将调用该函数的结果存储在堆栈分配的变量中。例如:
#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. */
}
是否可以进行此类过滤,如果可以,我该怎么做?
答案 0 :(得分:1)
好的。我看到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
中),这将成为下次调用{的输入{1}}等等:
std::copy_n
扩展到:
unpack { (ptr = std::copy_n(slices.data(), slices.size(), ptr)) ... } ;
请注意,由于它使用列表初始化,因此表达式评估的顺序保证是从左到右,即自上而下扩展形式!
由于GCC has bug since 4.7.0(这就是为什么它当前不起作用),你可以这样写:
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)),
};
另一个改进是:我会实现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<>
比sum
更可重用。
答案 1 :(得分:0)
您可以使用auto
和接受参数包的函数来生成必需的元组。例如,std::make_tuple
工作正常:
#include <string>
#include <utility>
char const* format_value(double x) { /* ... */ }
std::string format_value(long x) { /* ... */ }
template <typename Sink, typename... Values>
Sink& format(Sink& target, Values... values)
{
auto slices = std::make_tuple(format_value(values)...);
/* Code that does things with the results. */
}
同样,您也可以通过转发到另一个函数来完全避免使用元组。例如:
#include <string>
char const* format_value(double x) { /* ... */ }
std::string format_value(long x) { /* ... */ }
template <typename Sink, typename... Results>
void format_impl(Sink& target, Results... results)
{
/* Code that does things with the results. */
}
template <typename Sink, typename... Values>
Sink& format(Sink& target, Values... values)
{
format_impl(target, format_value(values)...);
return sink;
}