是否可以将“B<get_item<0,Ts...>>”更改为“template_with_params<B, 1, ...Ts>”?
Is it possible to change `B<get_item<0,Ts...>>` to `template_with_params<B, 1, ...Ts>`?
我正在开发一个 SFINAE 程序,如果参数 class 或模板 class 不是集合的基础,则从程序中删除函数模板实例(参见 How to get a SFINAE expression to work with template and non-template classes?) :
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Classes to test on
class A{};
template <typename T> class B{};
template <typename T0, typename T1> class BB{};
class C{};
template <typename T> class D{};
template <typename T0, typename T1> class DD{};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Collection of valid types
template <
template <typename...> class TT
, typename...Ts>
class collection
: A // class A
, B<get_item<0,Ts...>> // class B<X>
, BB<get_item<0,Ts...>, get_item<1,Ts...>> // class BB<Y, Z>
{};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Function to enable on
template <typename T>
enable_if_is_base_of<T, collection> test(T&&)
{ return enable_if_is_base_of<T, collection>();
}
现在我想知道 B<X>
或 BB<Y,Z>
的规范是否可以以某种方式从 BB<get_item<0,Ts...>, get_item<1,Ts...>>
反转为 template_with_params<BB, X, 2, ...Ts>
其中 returns 是 BB<T0, T1>
的类型,其中 T0
是 Ts...
的第一个模板参数,而 T1
是 [= 的第二个模板参数21=]。此外,如果 Ts
中没有足够的元素,则将使用默认的 X
来处理其余部分。可能吗?
#include <cstddef>
#include <utility>
#include <type_traits>
#include <tuple>
template <std::size_t... Is>
struct index_sequence {};
template <std::size_t N, std::size_t... Is>
struct make_index_sequence_h : make_index_sequence_h<N - 1, N - 1, Is...> {};
template <std::size_t... Is>
struct make_index_sequence_h<0, Is...> { using type = index_sequence<Is...>; };
template <std::size_t N>
using make_index_sequence = typename make_index_sequence_h<N>::type;
template <template <typename...> class T, typename D, std::size_t N, typename... Ts>
struct template_with_params_impl;
template <template <typename...> class T, typename D, std::size_t N, std::size_t... Is, std::size_t... Js, typename... Ts>
struct template_with_params_impl<T, D, N, index_sequence<Is...>, index_sequence<Js...>, Ts...>
{
using type = T<typename std::tuple_element<Is, std::tuple<Ts...>>::type..., typename std::remove_reference<decltype(void(Js), std::declval<D>())>::type...>;
};
template <template <typename...> class T, typename D, std::size_t N, typename... Ts>
using template_with_params = typename template_with_params_impl<T, D, N, make_index_sequence<sizeof...(Ts) >= N ? N : sizeof...(Ts)>, make_index_sequence<sizeof...(Ts) >= N ? 0 : N - sizeof...(Ts)>, Ts...>::type;
// if you want `void' to be the hardcoded default parameter, use below alias instead:
// template <template <typename...> class T, std::size_t N, typename... Ts>
// using template_with_params = typename template_with_params_impl<T, void, N, make_index_sequence<sizeof...(Ts) >= N ? N : sizeof...(Ts)>, make_index_sequence<sizeof...(Ts) >= N ? 0 : N - sizeof...(Ts)>, Ts...>::type;
测试:
#include <iostream>
template <typename... Ts>
struct B { void foo() { std::cout << 1; } };
int main()
{
template_with_params<B, void, 3, int> b{}; b.foo(); // 1
static_assert(std::is_same< template_with_params<B, void, 3, int>,
B<int, void, void> >{}, "!");
static_assert(std::is_same< template_with_params<B, void, 1, int, float>,
B<int> >{}, "!");
}
可以用递归来实现,一个接一个地应用参数:
// Apply a single type parameter to a template, producing a new template
template<template<typename...> class TT, typename T>
struct apply_partial {
template<typename... Ts>
using type = TT<T, Ts...>;
};
// Apply parameters from I upto N, one after another, using apply_partial
template<template<typename...> class TT, std::size_t I, std::size_t N, typename... Ts>
struct apply_seq {
typedef typename apply_seq<
apply_partial<TT, get_item<I, Ts...>>::template type,
I+1, N, Ts...
>::type type;
};
template<template<typename...> class TT, std::size_t N, typename... Ts>
struct apply_seq<TT, N, N, Ts...> {
typedef TT<> type;
};
// Main template
template<template<typename...> class TT, std::size_t N, typename... Ts>
using template_with_params = typename apply_seq<TT, 0, N, Ts...>::type;
它可以编译,但我还没有广泛测试它。还可以通过 apply_seq
.
的其他模板参数和特化来添加默认值等其他功能
对于 void
默认值,您需要添加这种情况:
template<template<typename...> class TT, std::size_t I, std::size_t N>
struct apply_seq<TT, I, N> {
typedef typename apply_seq<TT, I, N, void>::type type;
};
我正在开发一个 SFINAE 程序,如果参数 class 或模板 class 不是集合的基础,则从程序中删除函数模板实例(参见 How to get a SFINAE expression to work with template and non-template classes?) :
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Classes to test on
class A{};
template <typename T> class B{};
template <typename T0, typename T1> class BB{};
class C{};
template <typename T> class D{};
template <typename T0, typename T1> class DD{};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Collection of valid types
template <
template <typename...> class TT
, typename...Ts>
class collection
: A // class A
, B<get_item<0,Ts...>> // class B<X>
, BB<get_item<0,Ts...>, get_item<1,Ts...>> // class BB<Y, Z>
{};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Function to enable on
template <typename T>
enable_if_is_base_of<T, collection> test(T&&)
{ return enable_if_is_base_of<T, collection>();
}
现在我想知道 B<X>
或 BB<Y,Z>
的规范是否可以以某种方式从 BB<get_item<0,Ts...>, get_item<1,Ts...>>
反转为 template_with_params<BB, X, 2, ...Ts>
其中 returns 是 BB<T0, T1>
的类型,其中 T0
是 Ts...
的第一个模板参数,而 T1
是 [= 的第二个模板参数21=]。此外,如果 Ts
中没有足够的元素,则将使用默认的 X
来处理其余部分。可能吗?
#include <cstddef>
#include <utility>
#include <type_traits>
#include <tuple>
template <std::size_t... Is>
struct index_sequence {};
template <std::size_t N, std::size_t... Is>
struct make_index_sequence_h : make_index_sequence_h<N - 1, N - 1, Is...> {};
template <std::size_t... Is>
struct make_index_sequence_h<0, Is...> { using type = index_sequence<Is...>; };
template <std::size_t N>
using make_index_sequence = typename make_index_sequence_h<N>::type;
template <template <typename...> class T, typename D, std::size_t N, typename... Ts>
struct template_with_params_impl;
template <template <typename...> class T, typename D, std::size_t N, std::size_t... Is, std::size_t... Js, typename... Ts>
struct template_with_params_impl<T, D, N, index_sequence<Is...>, index_sequence<Js...>, Ts...>
{
using type = T<typename std::tuple_element<Is, std::tuple<Ts...>>::type..., typename std::remove_reference<decltype(void(Js), std::declval<D>())>::type...>;
};
template <template <typename...> class T, typename D, std::size_t N, typename... Ts>
using template_with_params = typename template_with_params_impl<T, D, N, make_index_sequence<sizeof...(Ts) >= N ? N : sizeof...(Ts)>, make_index_sequence<sizeof...(Ts) >= N ? 0 : N - sizeof...(Ts)>, Ts...>::type;
// if you want `void' to be the hardcoded default parameter, use below alias instead:
// template <template <typename...> class T, std::size_t N, typename... Ts>
// using template_with_params = typename template_with_params_impl<T, void, N, make_index_sequence<sizeof...(Ts) >= N ? N : sizeof...(Ts)>, make_index_sequence<sizeof...(Ts) >= N ? 0 : N - sizeof...(Ts)>, Ts...>::type;
测试:
#include <iostream>
template <typename... Ts>
struct B { void foo() { std::cout << 1; } };
int main()
{
template_with_params<B, void, 3, int> b{}; b.foo(); // 1
static_assert(std::is_same< template_with_params<B, void, 3, int>,
B<int, void, void> >{}, "!");
static_assert(std::is_same< template_with_params<B, void, 1, int, float>,
B<int> >{}, "!");
}
可以用递归来实现,一个接一个地应用参数:
// Apply a single type parameter to a template, producing a new template
template<template<typename...> class TT, typename T>
struct apply_partial {
template<typename... Ts>
using type = TT<T, Ts...>;
};
// Apply parameters from I upto N, one after another, using apply_partial
template<template<typename...> class TT, std::size_t I, std::size_t N, typename... Ts>
struct apply_seq {
typedef typename apply_seq<
apply_partial<TT, get_item<I, Ts...>>::template type,
I+1, N, Ts...
>::type type;
};
template<template<typename...> class TT, std::size_t N, typename... Ts>
struct apply_seq<TT, N, N, Ts...> {
typedef TT<> type;
};
// Main template
template<template<typename...> class TT, std::size_t N, typename... Ts>
using template_with_params = typename apply_seq<TT, 0, N, Ts...>::type;
它可以编译,但我还没有广泛测试它。还可以通过 apply_seq
.
对于 void
默认值,您需要添加这种情况:
template<template<typename...> class TT, std::size_t I, std::size_t N>
struct apply_seq<TT, I, N> {
typedef typename apply_seq<TT, I, N, void>::type type;
};