Vin*_*ent 7 c++ templates overloading template-meta-programming c++14
此前的答案显示了如何根据呼叫的有效性应用功能:此处.但是,它适用于两个功能.N在C++ 14中,我想知道这个概念是否可以推广到使用智能模板编程技巧的函数.
问题如下:
template <std::size_t N, class... X>
/* [Return type] */ apply_on_validity(X&&... x)
{
// Tricks here
}
// The function would be equivalent to a hypothetical
// template <std::size_t N, class... F, class... Args>
// [Return type] apply_on_validity(F&&... f, Args&&... args)
// where N = sizeof...(F) is the number of functions
Run Code Online (Sandbox Code Playgroud)
在执行方面:
apply_on_validity<3>(f1, f2, f3, a, b, c, d, e);
Run Code Online (Sandbox Code Playgroud)
将:
f1(a, b, c, d, e)如果表达式有效则调用,否则调用f2(a, b, c, d, e)如果表达式有效则调用,否则调用f3(a, b, c, d, e)如果表达式有效则调用,否则调用并且在所有情况下,它将返回已执行函数的结果.
在调用端,template参数3指示已指定的函数数.
它在C++ 14中是否可行,如果是这样,怎么样?
在c ++ 14中:
#include <tuple>
#include <utility>
#include <type_traits>
#include <cstddef>
template <std::size_t N, std::size_t... Js, typename Args>
auto apply_on_validity_impl(int, std::integral_constant<std::size_t, N>, std::index_sequence<Js...>, Args&& args)
{
// Nothing here
}
template <std::size_t N, std::size_t I, std::size_t... Js, typename Args>
auto apply_on_validity_impl(int, std::integral_constant<std::size_t, I>, std::index_sequence<Js...>, Args&& args)
-> decltype(std::get<I>(std::forward<Args>(args))(std::get<Js + N>(std::forward<Args>(args))...))
{
return std::get<I>(std::forward<Args>(args))(std::get<Js + N>(std::forward<Args>(args))...);
}
template <std::size_t N, std::size_t I, std::size_t... Js, typename Args>
decltype(auto) apply_on_validity_impl(char, std::integral_constant<std::size_t, I>, std::index_sequence<Js...> seq, Args&& args)
{
return apply_on_validity_impl<N>(0, std::integral_constant<std::size_t, I + 1>{}, seq, std::forward<Args>(args));
}
template <std::size_t N, typename... Args>
decltype(auto) apply_on_validity(Args&&... args)
{
return apply_on_validity_impl<N>(0, std::integral_constant<std::size_t, 0>{}, std::make_index_sequence<sizeof...(Args) - N>{}, std::forward_as_tuple(std::forward<Args>(args)...));
}
Run Code Online (Sandbox Code Playgroud)
在c ++ 17中:
#include <tuple>
#include <utility>
#include <type_traits>
#include <cstddef>
template <std::size_t N, std::size_t I, std::size_t... Js, typename Args>
decltype(auto) apply_on_validity_impl(std::index_sequence<Js...> seq, Args&& args)
{
if constexpr (I == N)
{
}
else if constexpr (std::is_invocable_v<std::tuple_element_t<I, Args>, std::tuple_element_t<Js + N, Args>...>)
{
return std::get<I>(std::forward<Args>(args))(std::get<Js + N>(std::forward<Args>(args))...);
}
else
{
return apply_on_validity_impl<N, I + 1>(seq, std::forward<Args>(args));
}
}
template <std::size_t N, typename... Args>
decltype(auto) apply_on_validity(Args&&... args)
{
return apply_on_validity_impl<N, 0>(std::make_index_sequence<sizeof...(Args) - N>{}, std::forward_as_tuple(std::forward<Args>(args)...));
}
Run Code Online (Sandbox Code Playgroud)
您使用的语法有点尴尬,因为您必须确切知道您拥有多少函数.结合Piotr Skotnicki的解决方案,解决了这个问题:
// Would be a local class except for the fact that it needs
// to have templates, thus can't be local to the function.
template<class... Fs>
class apply_first_f final {
public:
apply_first_f(Fs&&... fs)
: fs_{ std::forward<Fs>(fs)... }
{}
template<class... Args>
decltype(auto) operator()(Args&&... args) const
{
return apply_impl<sizeof...(Args)>(std::make_index_sequence<sizeof...(Fs)>{}, std::forward_as_tuple(std::forward<Args>(args)...));
}
private:
std::tuple<std::decay_t<Fs>...> fs_;
template<size_t argsSize, size_t... Is, class Args>
decltype(auto) apply_impl(std::index_sequence<Is...>, Args&& args) const
{
return apply_on_validity_impl<sizeof...(Fs)>(
0,
std::integral_constant<size_t, 0>{},
std::make_index_sequence<argsSize>{},
std::tuple_cat(
std::forward_as_tuple(std::get<Is>(fs_)...),
std::forward<Args>(args)
)
);
}
};
template<class... Fs>
auto make_apply_first_valid_f(Fs&&... fs)
{
return apply_first_f<Fs...>{ std::forward<Fs>(fs)... };
}
Run Code Online (Sandbox Code Playgroud)
功能可以这样使用:
make_apply_first_valid_f(f1, f2, f3)(args);
Run Code Online (Sandbox Code Playgroud)
DEMO(改编自Piotr的演示)
将它与Piotr的C++ 1z示例一起使用只需要进行一些小改动:
template<class... Fs>
class apply_first_f final {
// ...
template<size_t argsSize, size_t... Is, class Args>
decltype(auto) apply_impl(std::index_sequence<Is...>, Args&& args) const
{
return apply_on_validity_impl<sizeof...(Fs), /* added */ 0>(
/* 0, */
/* std::integral_constant<size_t, 0>{}, */
std::make_index_sequence<argsSize>{},
std::tuple_cat(
std::forward_as_tuple(std::get<Is>(fs_)...),
std::forward<Args>(args)
)
);
}
// ...
};
Run Code Online (Sandbox Code Playgroud)
这是另一个有趣的踢,滥用重载决议.我们要将每个函数转换为另一个函数,该函数接受一个rank参数,将所有函数组合在一起,然后只调用它们.选择将自然从过载集中消失.
我们的排名只是这种类型的阶梯:
template <int I> struct rank : rank<I-1> { };
template <> struct rank<0> { };
Run Code Online (Sandbox Code Playgroud)
我们需要一个功能变换器:
template <class T, class F>
auto prepend_arg(F&& f) {
return [f=std::forward<F>(f)](T, auto&&... args)
-> decltype(std::forward<F>(f)(std::forward<decltype(args)>(args)...))
{
return std::forward<F>(f)(std::forward<decltype(args)>(args)...);
};
}
Run Code Online (Sandbox Code Playgroud)
然后:
template <std::size_t N, std::size_t... Is, std::size_t... Js,
class... X>
decltype(auto) apply_impl(std::index_sequence<Is...>,
std::index_sequence<Js...>,
X&&... x)
{
auto all = std::forward_as_tuple(std::forward<X>(x)...);
return overload(
// all of our function cases
prepend_arg<rank<N-Is>>(std::get<Is>(all))...,
// base case: do nothing
[](rank<0>, auto&&...) {}
)(rank<N>{}, std::get<N+Js>(all)...);
// ^^^^^^^^^^^^^^^^^^^^^^^^
// pass in all the arguments
}
template <std::size_t N, class... X>
decltype(auto) apply_on_validity(X&&... x) {
return apply_impl<N>(
std::make_index_sequence<N>{},
std::make_index_sequence<sizeof...(X)-N>{},
std::forward<X>(x)...);
}
Run Code Online (Sandbox Code Playgroud)
我overload()作为练习离开.
| 归档时间: |
|
| 查看次数: |
378 次 |
| 最近记录: |