我尝试了以下代码,但它给出了:
main.cpp:29:22:错误:聚合'pop<std::tuple<int, char, float> > p'
类型不完整且无法定义
我错过了什么?
template <typename T>
struct pop;
template <typename E, typename... Ts>
struct pop<tuple<Ts..., E>> {
using result = tuple<Ts...>;
};
tuple<int, char, float> t;
typename pop<decltype(t)>::result p;
如果Ts ...必须在类型列表的最后,那么为什么它在http://en.cppreference.com/w/cpp/language/parameter_pack的这个例子中起作用:
template<class A, class B, class...C> void func(A arg1, B arg2, C...arg3)
{
container<A,B,C...> t1; // expands to container<A,B,E1,E2,E3>
container<C...,A,B> t2; // expands to container<E1,E2,E3,A,B>
container<A,C...,B> t3; // expands to container<A,E1,E2,E3,B>
}
答案 0 :(得分:5)
tuple<Ts..., E>
是一个非推断的上下文。 [temp.deduct.type] / 9:
如果
P
的表单包含<T>
或<i>
,那么相应模板参数列表{{}的每个参数P
i 1}}与P
的相应模板参数列表的相应参数A
i 进行比较。 如果A
的模板参数列表包含的包扩展不是最后一个模板参数,则整个模板参数列表是非推断的上下文。
这意味着您的部分专业化从不匹配。
使用C ++ 14,可以使用
P
这样
template <class T, class=std::make_index_sequence<std::tuple_size<T>::value-1>>
struct pop;
template <typename Tuple, std::size_t... indices>
struct pop<Tuple, std::index_sequence<indices...>>
{
using type = std::tuple<std::tuple_element_t<indices, Tuple>...>;
};
template <typename T>
using pop_t = typename pop<T>::type;
编译。
答案 1 :(得分:3)
Ts...
必须是类型列表的最后一个元素,如果您希望它被推导出来。 tuple<Ts...,E>
不会推断Ts...
只是最后一个,而是永远不会匹配。
摆脱最后一个参数有点过时了。 live example:
#include <iostream>
#include <tuple>
#include <iostream>
namespace details {
template<class Lhs, class Rhs>
struct pop_helper;
template<template<class...>class Tup, class L0, class...Lhs, class...Rhs>
struct pop_helper<Tup<L0,Lhs...>, Tup<Rhs...>>:
pop_helper<Tup<Lhs...>, Tup<Rhs...,L0>>
{};
template<template<class...>class Tup, class L0, class...Rhs>
struct pop_helper<Tup<L0>, Tup<Rhs...>> {
using type=Tup<Rhs...>;
};
}
template <typename T>
struct pop;
template<template<class...>class Tup, class...Ts>
struct pop<Tup<Ts...>>:
details::pop_helper<Tup<Ts...>,Tup<>>
{};
template<typename T>
using pop_t=typename pop<T>::type;
std::tuple<int, char, float> t;
typedef pop_t<decltype(t)> p;
int main() {
p x = std::make_tuple( 7, 'x' );
std::cout << std::get<0>(x) << std::get<1>(x) << std::tuple_size<p>{} << "\n";
}
pop_helper
将类型一次一个地移动到右侧,直到左侧只剩下一种类型。然后它返回右侧类型。
pop
只是传递了元组。
我使用template<class...>class Tup
代替std::tuple
,因为为什么不支持几乎每个template
而不仅仅支持std::tuple
?
pop_t
在使用时摆脱了恼人的typename
垃圾邮件。
我使用inhertance-as-type-map-forwarding模式,这节省了打字。使用类型映射,结构:
template<class X>
struct bob: foo<X> {};
可以被理解为bob<X>
是foo<X>
。另一种选择是更详细的
template<class X>
struct bob {
using type = typename foo<X>::type;
};
扩展变量类型列表与匹配它们不同。在设计时,匹配保持简单,以使编译器供应商能够实现该功能。甚至可能还有棘手的问题&#34;它很棘手&#34;走那条路。
答案 2 :(得分:1)
另一种C ++ 11方法来修饰这只猫:
#include <tuple>
template<class Tuple>
struct pop;
template<>
struct pop<std::tuple<>>
{
using type = std::tuple<>;
};
template<typename T1>
struct pop<std::tuple<T1>>
{
using type = std::tuple<>;
};
template<typename First, typename... Rest>
struct pop<std::tuple<First,Rest...>>
{
using type =
decltype(std::tuple_cat(
std::declval<std::tuple<First>>(),
std::declval<typename pop<std::tuple<Rest...>>::type>()));
};
// Test...
static_assert(std::is_same<pop<std::tuple<>>::type,std::tuple<>>::value,"");
static_assert(std::is_same<pop<std::tuple<int>>::type,std::tuple<>>::value,"");
static_assert(
std::is_same<pop<std::tuple<int,char>>::type,std::tuple<int>>::value,"");
static_assert(
std::is_same<pop<std::tuple<int,char,float>>::type,
std::tuple<int,char>>::value,"");
static_assert(
std::is_same<pop<std::tuple<int,char,float,double>>::type,
std::tuple<int,char,float>>::value,"");
答案 3 :(得分:0)
这是我提出的解决方案:
template <typename T>
struct pop;
template <typename E, typename... Ts>
struct pop<std::tuple<E, Ts...>> {
using type = decltype(tuple_cat(
declval<tuple<E>>(),
declval<typename pop<tuple<Ts...>>::type>()
));
};
template <typename E>
struct pop<std::tuple<E>> {
using type = std::tuple<>;
};