take_from_args<foo<int, bool, char, float>, 0,2>::type
是要
foo<int, char>
基于位置 0 和 2。实现很简单:
template <typename Class, std::size_t... Positions>
struct take_from_args;
template <template <typename...> class P, typename... Ts, std::size_t... Is>
struct take_from_args<P<Ts...>, Is...> {
using type = P<std::tuple_element_t<Is, std::tuple<Ts...>>...>;
};
现在,让我们尝试将其应用于此类:
template <int V, bool B, typename... Args>
struct bar {};
问题是bar
的int和bool参数, 所以它不能传递到 take_from_args
.所以让我们定义:
template <int V, bool B>
struct bar_h {
template <typename... Args>
using templ = bar<V, B, Args...>;
};
不幸的是,take_from_args<bar_h<5, true>::templ<int, bool, char, float>, 0,2>::type
不会编译。如何重新定义 take_from_args
这样它就可以像bar
这样的模板类?
我的整个代码:
#include <tuple>
template <typename Class, std::size_t... Positions> struct take_from_args;
template <template <typename...> class P, typename... Ts, std::size_t... Is>
struct take_from_args<P<Ts...>, Is...> {
using type = P<std::tuple_element_t<Is, std::tuple<Ts...>>...>;
};
// Testing
template <typename... Args>
struct foo {};
template <int V, bool B, typename... Args>
struct bar {};
template <int V, bool B>
struct bar_h {
template <typename... Args>
using templ = bar<V, B, Args...>;
};
int main() {
static_assert(std::is_same<
take_from_args<foo<int, bool, char, float>, 0,2>::type,
foo<int, char>>::value);
// static_assert(std::is_same<
// take_from_args<bar_h<5, true>::templ<int, bool, char, float>, 0,2>::type,
// bar<5, true, int, char>>::value);
}
最佳答案
您使用 bar_h
的解决方法不起作用,因为 bar_h<5, true>::templ<int, bool, char, float>
只是 bar<5, true, int, bool, char, float>
的别名 :
static_assert(// compiles without error
std::is_same_v<
bar_h<5, true>::templ<int, bool, char, float>,
bar<5, true, int, bool, char, float>
>
);
我看到两个选项:
1。避免在 `bar` 中使用非类型模板参数
编辑:当您在 your answer 中遵循此方法时,但我经历了issues with clang : 这是一个修改版本 works for me使用 GCC 7.2 和 Clang 5.0。
template<auto...> struct Vals {};
template<class T>
struct HasVals : std::false_type {};
template<auto... Vs>
struct HasVals<Vals<Vs...>> : std::true_type {};
template<class T, size_t... is>
struct take_from_args;
template<template<class...> class P, class... Ts, size_t... is>
struct take_from_args<P<Ts...>, is...> {
// convention: pass-through first argument if it `HasVals`
using Vs = std::tuple_element_t<0, std::tuple<Ts...>>;
using type = std::conditional_t<
HasVals<Vs>::value,
P<Vs, std::tuple_element_t<1u+is, std::tuple<Ts...>>...>,
P<std::tuple_element_t<is, std::tuple<Ts...>>...>
>;
};
// Testing
template<class Vs, class... Args>
struct bar;
template<int v, bool b, class... Args>
struct bar<Vals<v, b>, Args...> {
static constexpr int value = v;
static constexpr bool truth = b;
};
2. 为 `take_from_args` 提供更多特化
既然你特别要求后者,这里有一个例子:
// there could be 1 value(s) at the beginning...
template<
template<auto, auto, typename...> class P,
auto v0, class... Ts, std::size_t... is
> struct take_from_args<P<v0, Ts...>, is...> {
using type = P<v0, std::tuple_element_t<is, std::tuple<Ts...>>...>;
};
// ... 2 ...
template<
template<auto, auto, typename...> class P,
auto v0, auto v1, class... Ts, std::size_t... is
> struct take_from_args<P<v0, v1, Ts...>, is...> {
using type = P<v0, v1, std::tuple_element_t<is, std::tuple<Ts...>>...>;
};
// ... 3 ... and more?
template<
template<auto, auto, typename...> class P,
auto v0, auto v1, auto v2, class... Ts, std::size_t... is
> struct take_from_args<P<v0, v1, v2, Ts...>, is...> {
using type = P<v0, v1, v2, std::tuple_element_t<is, std::tuple<Ts...>>...>;
};
不幸的是,我没有成功使用 auto...
用于推导前导模板参数。
关于c++ - 基于位置的包中的特定类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46867004/