2016-04-22 51 views
0

更改模板,讓我們定義,change_templates如下面的例子:對於給定的</p> <pre><code>template <typename...> class P; template <typename...> class Q; template <typename...> class R; template <typename...> class S; </code></pre> <p>包

change_templates<P<int, char, R<double, int>, bool>, P,Q, R,S>::type 

是要

Q<int, char, S<double, int>, bool> 

更普遍,

change_templates<P<int, Q<int, int>, char, P<double, P<char, char>, int>, bool>, P,Q, P,R, Q,S>::type 

是要

Q<int, S<int, int>, char, R<double, P<char, char>, int>, bool> 

(請注意,缺乏第三P,...對意味着第三P是保持不變,雖然P,P可以代替無論如何使用)。好消息是,我有它具有以下工作:

#include <iostream> 
#include <type_traits> 

template <template <typename...> class...> struct TP; 

template <template <typename...> class, typename Templates, typename Checked = TP<>> struct find_template; 

template <template <typename...> class P, template <typename...> class Q, 
    template <typename...> class... Rest, template <typename...> class... Checked> 
struct find_template<P, TP<Q, Rest...>, TP<Checked...>> : 
    find_template<P, TP<Rest...>, TP<Checked..., Q>> {}; // Search the next template by default. 

template <template <typename...> class P, template <typename...> class Q, 
    template <typename...> class... Rest, template <typename...> class... Checked> 
struct find_template<P, TP<P, Q, Rest...>, TP<Checked...>> { // Q follows P, which means that P is to change to Q. 
    template <typename... Ts> 
    using type = Q<Ts...>; 
    using remaining_templates = TP<Checked..., Rest...>; // Every template except P,Q kept for later searches, since they have been used now. 
}; 

template <template <typename...> class P, template <typename...> class... Checked> 
struct find_template<P, TP<>, TP<Checked...>> { // P not found. 
    template <typename... Ts> 
    using type = P<Ts...>; // P not found, so simply don't change P. 
    using remaining_templates = TP<Checked...>; 
}; 

template <typename T, template <typename...> class... Templates> 
struct change_templates { 
    using type = T; // Base case. A non-pack type remains unchanged. 
}; 

template <typename T, typename Templates> struct change_templates_impl; 

template <typename T, template <typename...> class... Templates> 
struct change_templates_impl<T, TP<Templates...>> : 
    change_templates<T, Templates...> {}; 

template <template <typename...> class P, typename... Ts, template <typename...> class... Templates> 
struct change_templates<P<Ts...>, Templates...> { // A pack of types (possibly of other packs). 
    using F = find_template<P, TP<Templates...>>; 
    using Remaining = typename F::remaining_templates; // To be passed on for the next find_template call. 
    using type = typename F::template type<typename change_templates_impl<Ts, Remaining>::type...>; // Recursive call. 
}; 

// Testing 
template <typename...> class P; template <typename...> class Q; 
template <typename...> class R; template <typename...> class S; 

int main() { 
    static_assert (std::is_same<change_templates<P<int, char, double>, P, Q>::type, Q<int, char, double>>::value, ""); 

    static_assert (std::is_same< 
     change_templates<P<int, char, R<double, int>, bool>, P,Q, R,S>::type, 
     Q<int, char, S<double, int>, bool> 
    >::value, ""); 

    static_assert (std::is_same< 
     change_templates<P<int, Q<int, int>, char, P<double, P<char, char>, int>, bool>, P,Q, P,R, Q,S>::type, // The third P in the pack is unchanged because there is no pair for the third P. 
     Q<int, S<int, int>, char, R<double, P<char, char>, int>, bool> 
    >::value, ""); 
} 

但現在我當然希望以下內容:

template <int...> class I; template <int...> class J; 

int main() { 
    static_assert (std::is_same< 
     change_templates<P<int, char, I<4,5>, bool>, P,Q, I,J>::type, 
     Q<int, char, J<4,5>, bool> 
    >::value, ""); 
} 

但我不知道如何去適應我上面的代碼來處理這個,因爲P,Q是類型的模板,而I,J是int的模板(或者更一般地說是任何整型)。有沒有辦法使不同類型的模板均勻化,以使上述內容按照預期工作(或者語法略有不同)?如果我們在同一包裝中同時包含int包裝和std::size_t等包裝?

+4

我忍不住說「這段代碼看起來非常難以維護」 –

+0

您可以使用'4'的std :: integral_constant 'int作爲解決方法嗎? – Jarod42

回答

0

以下解決方案對我來說是半滿意的。現在至少所有不同類型的模板被均化爲類型,並且現在滿足了特定的靜態斷言。如果有人能夠引導我如何在change_templates的最後部分專業化中推廣int,它可能會消除Murat Karakus提出的解決方案的「不可維護」方面。

#include <iostream> 
#include <type_traits> 
#include <tuple> 

template <template <typename...> class...> struct K; 
template <typename T, template <T...> class...> struct L; 

template <typename Find, typename Templates, typename Checked = std::tuple<>> struct find_template; 

template <typename FindMe, template <typename...> class Z, typename Mismatch, typename... Rest, typename... Checked> 
struct find_template<FindMe, Z<Mismatch, Rest...>, Z<Checked...>> : find_template<FindMe, Z<Rest...>, Z<Checked..., Mismatch>> {}; // Search the next template by default. 

template <template <typename...> class P, template <typename...> class Z, template <typename...> class Q, typename... Rest, typename... Checked> 
struct find_template<K<P>, Z<K<P,Q>, Rest...>, Z<Checked...>> { // Q follows P, which means that P is to change to Q. 
    template <typename... Ts> 
    using type = Q<Ts...>; 
    using remaining_templates = Z<Checked..., Rest...>; // Every template except P,Q kept for later searches, since they have been used now. 
}; 

template <typename T, template <T...> class P, template <typename...> class Z, template <T...> class Q, typename... Rest, typename... Checked> 
struct find_template<L<T,P>, Z<L<T,P,Q>, Rest...>, Z<Checked...>> { // Q follows P, which means that P is to change to Q. 
    template <T... Is> 
    using type = Q<Is...>; 
    using remaining_templates = Z<Checked..., Rest...>; // Every template except P,Q kept for later searches, since they have been used now. 
}; 

template <template <typename...> class P, template <typename...> class Z, typename... Checked> 
struct find_template<K<P>, Z<>, Z<Checked...>> { // P not found. 
    template <typename... Ts> 
    using type = P<Ts...>; // P not found, so simply don't change P. 
    using remaining_templates = Z<Checked...>; 
}; 

template <typename T, typename... Templates> 
struct change_templates { 
    using type = T; // Base case. A non-pack type remains unchanged. 
}; 

template <typename T, typename Templates> struct change_templates_impl; 

template <typename T, template <typename...> class Z, typename... Templates> 
struct change_templates_impl<T, Z<Templates...>> : change_templates<T, Templates...> {}; 

template <template <typename...> class P, typename... Ts, typename... Templates> 
struct change_templates<P<Ts...>, Templates...> { // A pack of types (possibly of other packs). 
    using F = find_template<K<P>, std::tuple<Templates...>>; 
    using Remaining = typename F::remaining_templates; // To be passed on for the next find_template call. 
    using type = typename F::template type<typename change_templates_impl<Ts, Remaining>::type...>; // Recursive call. 
}; 

template <template <int...> class P, int... Is, typename... Templates> 
struct change_templates<P<Is...>, Templates...> { // A pack of integral non-types. 
    using F = find_template<L<int,P>, std::tuple<Templates...>>; 
    using type = typename F::template type<Is...>; // Non-recursive call, since the Is... cannot themselves be packs. 
}; 

// Testing 
template <typename...> class P; template <typename...> class Q; 
template <typename...> class R; template <typename...> class S; 
template <int...> class I; template <int...> class J; 

int main() { 
    static_assert (std::is_same<change_templates<P<int, char, double>, K<P,Q>>::type, Q<int, char, double>>::value, ""); 

    static_assert (std::is_same< 
     change_templates<P<int, char, R<double, int>, bool>, K<P,Q>, K<R,S>>::type, 
     Q<int, char, S<double, int>, bool> 
    >::value, ""); 

    static_assert (std::is_same< 
     change_templates<P<int, Q<int, int>, char, P<double, P<char, char>, int>, bool>, K<P,Q>, K<P,R>, K<Q,S>>::type, // The third P in the pack is unchanged because there is no K pair for the third P. 
     Q<int, S<int, int>, char, R<double, P<char, char>, int>, bool> 
    >::value, ""); 

    static_assert (std::is_same< 
     change_templates<P<int, char, I<4,5>, bool>, K<P,Q>, L<int,I,J>>::type, 
     Q<int, char, J<4,5>, bool> 
    >::value, ""); 
} 

更新:我意識到,推廣整型不能做,再比任何編譯器可以從函數推斷T

template <typename T, template <T...> class P, T... Is> 
T foo(P<Is...>); 

所以

template <template <int...> class P, int... Is, typename... Templates> 
struct change_templates<P<Is...>, Templates...> 

需要重複的其他整體類型。

相關問題