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);
}
答案 0 :(得分:2)
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>
>
);
我看到两个选项:
修改:正如您在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;
};
由于你特别要求后者,这里有一个例子:
// 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...
来扣除主要模板参数。
答案 1 :(得分:0)
遵循朱利叶斯关于重新设计班级bar
的最后建议:
#include <tuple>
#include <type_traits>
template <auto...> struct Vals {};
template <typename Class> struct HasVals : std::false_type {};
template <auto... Vs>
struct HasVals<Vals<Vs...>> : std::true_type {};
template <typename Class, std::size_t... Positions> struct take_from_args;
template <template <typename, typename...> class P, typename VALS, typename... Ts, std::size_t... Is>
struct take_from_args<P<VALS, Ts...>, Is...> {
using type = std::conditional_t<HasVals<VALS>::value,
P<VALS, std::tuple_element_t<Is, std::tuple<Ts...>>...>,
P<std::tuple_element_t<Is, std::tuple<VALS, Ts...>>...> // VALS is part of the tuple in this case
>;
};
// Testing
template <typename... Args>
struct foo {};
template <typename VALS, typename... Args>
struct bar;
template <int v, bool b, typename... Args>
struct bar<Vals<v, b>, Args...> {
static constexpr int value = v;
static constexpr bool truth = b;
};
int main() {
static_assert(std::is_same<
take_from_args<foo<int, bool, char, float>, 0,2>::type,
foo<int, char>>::value);
using new_bar = take_from_args<bar<Vals<5, true>, int, bool, char, float>, 0,2>::type;
static_assert(std::is_same<
new_bar,
bar<Vals<5, true>, int, char>>::value);
static_assert(new_bar::value == 5);
static_assert(new_bar::truth == true);
//static_assert(std::is_same<decltype(new_bar::value), int>::value); // why fails?
//static_assert(std::is_same<decltype(new_bar::truth), bool>::value);
}