2012-02-04 79 views
0

我想从另一个元组的前n个元素创建一个元组。这是我使用的递归(在这里不计算任何有用的东西)。这个模板专业为什么不在GCC中工作?

奇怪的是,它不能使用g ++ 4.6.1,尽管据我所知,front<0,…>front<n,…>更专业,应该选择它。这是一个错误还是我对专业化感到困惑?

#include <tuple> 

template<std::size_t, typename> 
struct front; 

#if 0 
// This works, but I only want one case. 
template<typename Head, typename... Tail> 
struct front<0, std::tuple<Head, Tail...>> { 
    typedef std::tuple<> type; 
}; 
template<typename Head> 
struct front<0, std::tuple<Head>> { 
    typedef std::tuple<> type; 
}; 
template<> 
struct front<0, std::tuple<>> { 
    typedef std::tuple<> type; 
}; 
#elseif 0 
// this doesn't work, but I don't understand why: 
// ambiguous class template instantiation, candidates are: 
// struct front<0u, std::tuple<_Elements ...> > 
// struct front<n, std::tuple<_Head, _Tail ...> > 
template<typename... Tail> 
struct front<0, std::tuple<Tail...>> { 
    typedef std::tuple<> type; 
}; 
#else 
// neither does this: 
// ambiguous class template instantiation, candidates are: 
// struct front<0u, T> 
// struct front<n, std::tuple<_Head, _Tail ...> > 
template<typename T> 
struct front<0, T> { 
    typedef std::tuple<> type; 
}; 
#endif 
// this makes no sense, but it's short. 
template<std::size_t n, typename Head, typename... Tail> 
struct front<n, std::tuple<Head, Tail...>> { 
    typedef typename front<n - 1, std::tuple<Tail...>>::type type; 
}; 
// check all cases, error includes calculated type: 
front<0, std::tuple<int, float, double, long>>::type x0 = 0; 
front<2, std::tuple<int, float, double, long>>::type x2 = 0; 
front<4, std::tuple<int, float, double, long>>::type x4 = 0; 

回答

2

模板参数不是从左到右挑选的。是的,0n更专业,但std::tuple<Head, Tail...>T更专业。您可以添加一个额外的专业化,这是最专业的两个参数:

#include <tuple> 

template<typename A, typename B> 
struct front_helper; 

template<typename... A, typename... B> 
struct front_helper<std::tuple<A...>, std::tuple<B...>> { 
    typedef std::tuple<A..., B...> type; 
}; 

template<std::size_t, typename> 
struct front; 

template<> 
struct front<0, std::tuple<>> { 
    typedef std::tuple<> type; 
}; 
template<typename Head, typename... Tail> 
struct front<0, std::tuple<Head, Tail...>> { 
    typedef std::tuple<> type; 
}; 
template<std::size_t n, typename Head, typename... Tail> 
struct front<n, std::tuple<Head, Tail...>> { 
    typedef typename front_helper<std::tuple<Head>, typename front<n-1, std::tuple<Tail...>>::type>::type type; 
}; 

void x0(front<0, std::tuple<int, float, double, long>>::type) { } 
void x1(front<1, std::tuple<int, float, double, long>>::type) { } 
void x2(front<2, std::tuple<int, float, double, long>>::type) { } 
void x3(front<3, std::tuple<int, float, double, long>>::type) { } 
void x4(front<4, std::tuple<int, float, double, long>>::type) { } 

$ g++ test.cc -c -std=c++0x && nm -C test.o 
00000000 b .bss 
00000000 d .data 
00000000 t .text 
00000000 T x0(std::tuple<>) 
00000005 T x1(std::tuple<int>) 
0000000a T x2(std::tuple<int, float>) 
0000000f T x3(std::tuple<int, float, double>) 
00000014 T x4(std::tuple<int, float, double, long>) 
00000000 b std::(anonymous namespace)::ignore