2014-01-28 8 views
9

Variadische Vorlage Template-Parameter akzeptieren jede Vorlage:Wie kann ich variable Template Vorlage Parameter curry?

template<typename T> 
struct Test1 { 
    using type = int; 
}; 

template<typename T, typename T1> 
struct Test2 { 
    using type = char*; 
}; 

template<template<typename...S> class BeCurry> 
struct Currying { 
}; 

using curry = Currying<Test1>; 
using curry2 = Currying<Test2>; 

I Currying Template-Template-Klasse wollen.
Dies bedeutet: wenn der Parameter einen Vorlagenparameter akzeptiert, wie Test1, curry::apply<T>::type get Test1<T>::type. Wenn der Parameter zwei Vorlagenparameter akzeptiert, wie Test2, curry2::apply<T0> ist eine "teilweise" Vorlage, curry2::apply<T0>::apply<T1>::type get Test2<T0,T1>::type

Ist dies möglich zu implementieren? Weil ich nicht innere Parameter Zahl der Template-Template-Parameter abfragen kann:

template<template<typename... S> class BeCurry> 
struct Currying { 
    enum { value = sizeof...(S) }; // error! 
}; 
+0

Bitte überprüfen –

Antwort

3

Einfache Lösung:

template 
    < 
     template <typename...> class BeCurry, 
     typename... Params 
    > 
struct Currying 
{ 
    template <typename... OtherParams> 
    using curried = BeCurry<Params..., OtherParams...>; 

    template <typename... OtherParams> 
    using type = typename curried<OtherParams...>::type; 

    template <typename... NewParams> 
    using apply = Currying<curried, NewParams...>; 
}; 

Aber es funktioniert nicht mit Vorlagen wie Test1 und Test2 wegen Übersetzungsfehlern (unter gcc, zumindest). Eine Abhilfe für dieses Problem sieht wie folgt aus:

template 
    < 
     template <typename...> class BeCurry, 
     typename... Params 
    > 
struct Curry 
{ 
    using type = BeCurry<Params...>; 
}; 

template 
    < 
     template <typename...> class BeCurry 
    > 
struct Curry<BeCurry> 
{ 
    using type = BeCurry<>; 
}; 

Und jetzt Linien

template <typename... OtherParams> 
using curried = BeCurry<Params..., OtherParams...>; 

sollten mit Linien

template <typename... OtherParams> 
using curried = typename Curry<BeCurry, Params..., OtherParams...>::type; 

Beispiel für die Verwendung ersetzt werden:

#include <iostream> 
#include <typeinfo> 

template <typename T> 
void print_type(T t) 
{ 
    std::cout << typeid(t).name() << std::endl; 
} 

// ... 

print_type(Currying<Test1>::type<int>{}); 
print_type(Currying<Test1>::apply<int>::type<>{}); 
print_type(Currying<Test2>::type<int, char>{}); 
print_type(Currying<Test2>::apply<int>::type<char>{}); 
print_type(Currying<Test2>::apply<int>::apply<char>::type<>{}); 
print_type(Currying<Test2>::apply<int, char>::type<>{}); 

Voll Beispiel bei ideone.

0

Nach some problems of my own, kam ich mit dieser Lösung, die für jede Vorlagenklasse (auch die, die Sie in Ihrem Beitrag bereitstellen) funktioniert.
Der Kern dieser Lösung ist is_valid_specialization, die als Bedingung verwendet wird, ob oder ob nicht der currying Prozess vollständige betrachtet werden kann:

#include <iostream> 
#include <type_traits> 

template<template<typename...> class C, typename... T> 
struct is_valid_specialization { 
    typedef struct { char _; } yes; 
    typedef struct { yes _[2]; } no; 

    template<template<typename...> class D> 
    static yes test(D<T...>*); 
    template<template<typename...> class D> 
    static no test(...); 

    constexpr static bool value = (sizeof(test<C>(0)) == sizeof(yes)); 
}; 

namespace detail { 

    template<template<typename...> class BeCurry, bool = false, typename... S> 
    struct Currying { 

     template<typename... T> 
     using apply = Currying<BeCurry, is_valid_specialization<BeCurry, S..., T...>::value, S..., T...>; 
    }; 

    template<template<typename...> class BeCurry, typename... S> 
    struct Currying<BeCurry, true, S...> { 

     template<typename... T> 
     using apply = Currying<BeCurry, is_valid_specialization<BeCurry, S..., T...>::value, S..., T...>; 

     using type = typename BeCurry<S...>::type; 
    }; 
} 

template<template<typename...> class BeCurry> 
using Currying = detail::Currying<BeCurry, is_valid_specialization<BeCurry>::value>; 

template<typename T> 
struct Test1 { using type = int; }; 

template<typename T1, typename T2> 
struct Test2 { using type = char*; }; 

template<typename...> 
struct Test3 { using type = double; }; 

using curry = Currying<Test1>; 
using curry2 = Currying<Test2>; 
using curry3 = Currying<Test3>; 

template<typename T> 
void pretty_print(T) { 
    std::cout << __PRETTY_FUNCTION__ << std::endl; 
} 

int main() { 
    pretty_print(typename curry::apply<char>::type{}); 
    pretty_print(typename curry2::apply<int>::apply<char>::type{}); 
    pretty_print(typename curry3::type{}); 
} 

Ausgabe am ideone

+0

meine aktualisierte Antwort ja, Ist am nächsten. Curry simulieren haskell function.all anwenden Schablone akzeptieren nur einen param (Ergebnis erzeugen oder erhalten eine "Partielle" anwenden) .wenn bewerben nicht einen inneren Typ haben, muss es eine Vorlage anwenden ... essen alle brauchen Param durch Erfolg. Vielleicht kann ich Erfolg basierend auf den Ergebnissen Ihrer ...... – fe263

Verwandte Themen