2012-02-04 81 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