我正在研究SFINAE程序,如果参数类或模板类不是集合的基础,则从程序中删除函数模板实例(参见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>
定义为collection
基础的规范是否会以某种方式从BB<get_item<0,Ts...>, get_item<1,Ts...>>
转换为template_with_params<BB, X, 2, ...Ts>
}返回BB<T0, T1>
类型,其中T0
是Ts...
中的第一个模板参数,T1
是来自Ts...
的第二个模板参数。此外,如果Ts
中没有足够的元素,则其余部分将使用默认的X
。可能的?
答案 0 :(得分:1)
#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> >{}, "!");
}