C ++ टेम्पलेट ट्यूरिंग-पूर्ण?


111

मुझे बताया गया है कि C ++ में टेम्प्लेट सिस्टम संकलन समय पर ट्यूरिंग-पूर्ण है। इस पोस्ट में और विकिपीडिया पर भी इसका उल्लेख किया गया है ।

क्या आप इस संपत्ति का शोषण करने वाले एक संगणना का एक गैर-उदाहरण उदाहरण प्रदान कर सकते हैं?

क्या यह तथ्य व्यवहार में उपयोगी है?

जवाबों:


110

उदाहरण

#include <iostream>

template <int N> struct Factorial
{
    enum { val = Factorial<N-1>::val * N };
};

template<>
struct Factorial<0>
{
    enum { val = 1 };
};

int main()
{
    // Note this value is generated at compile time.
    // Also note that most compilers have a limit on the depth of the recursion available.
    std::cout << Factorial<4>::val << "\n";
}

यह थोड़ा मजेदार था लेकिन बहुत व्यावहारिक नहीं था।

प्रश्न के दूसरे भाग का उत्तर देने के लिए:
क्या यह तथ्य व्यवहार में उपयोगी है?

संक्षिप्त उत्तर: क्रमबद्ध।

दीर्घ उत्तर: हां, लेकिन केवल यदि आप एक टेम्पलेट डेमॉन हैं।

टेम्प्लेट मेटा-प्रोग्रामिंग का उपयोग करके अच्छी प्रोग्रामिंग को चालू करने के लिए जो दूसरों के लिए उपयोग करने के लिए वास्तव में उपयोगी है (यानी एक पुस्तकालय) वास्तव में बहुत कठिन है (हालांकि सक्षम है)। यहां तक ​​कि बढ़ावा देने में मदद के लिए एमपीएल उर्फ (मेटा प्रोग्रामिंग लाइब्रेरी) भी है। लेकिन अपने टेम्प्लेट कोड में एक कंपाइलर त्रुटि डिबगिंग का प्रयास करें और आप एक लंबी हार्ड राइड के लिए होंगे।

लेकिन इसका एक अच्छा व्यावहारिक उदाहरण कुछ उपयोगी के लिए इस्तेमाल किया जा रहा है:

स्कॉट मेयर्स टेम्प्लेटिंग सुविधाओं का उपयोग करके सी ++ भाषा के लिए एक्सटेंशन का उपयोग कर रहा है (मैं शब्द का उपयोग शिथिल करता हूं)। आप यहां उनके काम के बारे में पढ़ सकते हैं ' एनफोर्सिंग कोड फीचर्स '


36
डांग वहाँ अवधारणाएँ (शिकार) गए
मार्टिन यॉर्क

5
मेरे पास केवल उपलब्ध उदाहरण के साथ एक छोटा मुद्दा है - यह C ++ के टेम्पलेट सिस्टम की पूर्ण (पूर्ण) ट्यूरिंग-पूर्णता का शोषण नहीं करता है। फैक्टरियल को आदिम पुनरावर्ती कार्यों का उपयोग करके भी पाया जा सकता है, जो कि ट्यूरिंग-पूर्ण नहीं हैं
Dalibor Frivaldsky

4
और अब हमारे पास अवधारणाएं हैं
nurettin

1
2017 में, हम अवधारणाओं को और भी पीछे धकेल रहे हैं। यहाँ 2020 के लिए उम्मीद है।
दीदी जूल

2
@ मार्केगेल 12 साल बाद: डी
विक्टर

181

मैंने C ++ 11 में एक ट्यूरिंग मशीन किया है। विशेषताएं जो C ++ 11 जोड़ती हैं, वे वास्तव में ट्यूरिंग मशीन के लिए महत्वपूर्ण नहीं हैं। यह सिर्फ मनमाना लंबाई नियम सूचियों के लिए प्रदान करता है, जो कि विकृत मैक्रो मेटाग्रोमिंग :) का उपयोग करने के बजाय, वैचारिक टेम्पलेट्स का उपयोग करता है। शर्तों के नाम का उपयोग स्टडआउट पर आरेख को आउटपुट करने के लिए किया जाता है। मैंने नमूना छोटा रखने के लिए उस कोड को निकाल दिया है।

#include <iostream>

template<bool C, typename A, typename B>
struct Conditional {
    typedef A type;
};

template<typename A, typename B>
struct Conditional<false, A, B> {
    typedef B type;
};

template<typename...>
struct ParameterPack;

template<bool C, typename = void>
struct EnableIf { };

template<typename Type>
struct EnableIf<true, Type> {
    typedef Type type;
};

template<typename T>
struct Identity {
    typedef T type;
};

// define a type list 
template<typename...>
struct TypeList;

template<typename T, typename... TT>
struct TypeList<T, TT...>  {
    typedef T type;
    typedef TypeList<TT...> tail;
};

template<>
struct TypeList<> {

};

template<typename List>
struct GetSize;

template<typename... Items>
struct GetSize<TypeList<Items...>> {
    enum { value = sizeof...(Items) };
};

template<typename... T>
struct ConcatList;

template<typename... First, typename... Second, typename... Tail>
struct ConcatList<TypeList<First...>, TypeList<Second...>, Tail...> {
    typedef typename ConcatList<TypeList<First..., Second...>, 
                                Tail...>::type type;
};

template<typename T>
struct ConcatList<T> {
    typedef T type;
};

template<typename NewItem, typename List>
struct AppendItem;

template<typename NewItem, typename...Items>
struct AppendItem<NewItem, TypeList<Items...>> {
    typedef TypeList<Items..., NewItem> type;
};

template<typename NewItem, typename List>
struct PrependItem;

template<typename NewItem, typename...Items>
struct PrependItem<NewItem, TypeList<Items...>> {
    typedef TypeList<NewItem, Items...> type;
};

template<typename List, int N, typename = void>
struct GetItem {
    static_assert(N > 0, "index cannot be negative");
    static_assert(GetSize<List>::value > 0, "index too high");
    typedef typename GetItem<typename List::tail, N-1>::type type;
};

template<typename List>
struct GetItem<List, 0> {
    static_assert(GetSize<List>::value > 0, "index too high");
    typedef typename List::type type;
};

template<typename List, template<typename, typename...> class Matcher, typename... Keys>
struct FindItem {
    static_assert(GetSize<List>::value > 0, "Could not match any item.");
    typedef typename List::type current_type;
    typedef typename Conditional<Matcher<current_type, Keys...>::value, 
                                 Identity<current_type>, // found!
                                 FindItem<typename List::tail, Matcher, Keys...>>
        ::type::type type;
};

template<typename List, int I, typename NewItem>
struct ReplaceItem {
    static_assert(I > 0, "index cannot be negative");
    static_assert(GetSize<List>::value > 0, "index too high");
    typedef typename PrependItem<typename List::type, 
                             typename ReplaceItem<typename List::tail, I-1,
                                                  NewItem>::type>
        ::type type;
};

template<typename NewItem, typename Type, typename... T>
struct ReplaceItem<TypeList<Type, T...>, 0, NewItem> {
    typedef TypeList<NewItem, T...> type;
};

enum Direction {
    Left = -1,
    Right = 1
};

template<typename OldState, typename Input, typename NewState, 
         typename Output, Direction Move>
struct Rule {
    typedef OldState old_state;
    typedef Input input;
    typedef NewState new_state;
    typedef Output output;
    static Direction const direction = Move;
};

template<typename A, typename B>
struct IsSame {
    enum { value = false }; 
};

template<typename A>
struct IsSame<A, A> {
    enum { value = true };
};

template<typename Input, typename State, int Position>
struct Configuration {
    typedef Input input;
    typedef State state;
    enum { position = Position };
};

template<int A, int B>
struct Max {
    enum { value = A > B ? A : B };
};

template<int n>
struct State {
    enum { value = n };
    static char const * name;
};

template<int n>
char const* State<n>::name = "unnamed";

struct QAccept {
    enum { value = -1 };
    static char const* name;
};

struct QReject {
    enum { value = -2 };
    static char const* name; 
};

#define DEF_STATE(ID, NAME) \
    typedef State<ID> NAME ; \
    NAME :: name = #NAME ;

template<int n>
struct Input {
    enum { value = n };
    static char const * name;

    template<int... I>
    struct Generate {
        typedef TypeList<Input<I>...> type;
    };
};

template<int n>
char const* Input<n>::name = "unnamed";

typedef Input<-1> InputBlank;

#define DEF_INPUT(ID, NAME) \
    typedef Input<ID> NAME ; \
    NAME :: name = #NAME ;

template<typename Config, typename Transitions, typename = void> 
struct Controller {
    typedef Config config;
    enum { position = config::position };

    typedef typename Conditional<
        static_cast<int>(GetSize<typename config::input>::value) 
            <= static_cast<int>(position),
        AppendItem<InputBlank, typename config::input>,
        Identity<typename config::input>>::type::type input;
    typedef typename config::state state;

    typedef typename GetItem<input, position>::type cell;

    template<typename Item, typename State, typename Cell>
    struct Matcher {
        typedef typename Item::old_state checking_state;
        typedef typename Item::input checking_input;
        enum { value = IsSame<State, checking_state>::value && 
                       IsSame<Cell,  checking_input>::value
        };
    };
    typedef typename FindItem<Transitions, Matcher, state, cell>::type rule;

    typedef typename ReplaceItem<input, position, typename rule::output>::type new_input;
    typedef typename rule::new_state new_state;
    typedef Configuration<new_input, 
                          new_state, 
                          Max<position + rule::direction, 0>::value> new_config;

    typedef Controller<new_config, Transitions> next_step;
    typedef typename next_step::end_config end_config;
    typedef typename next_step::end_input end_input;
    typedef typename next_step::end_state end_state;
    enum { end_position = next_step::position };
};

template<typename Input, typename State, int Position, typename Transitions>
struct Controller<Configuration<Input, State, Position>, Transitions, 
                  typename EnableIf<IsSame<State, QAccept>::value || 
                                    IsSame<State, QReject>::value>::type> {
    typedef Configuration<Input, State, Position> config;
    enum { position = config::position };
    typedef typename Conditional<
        static_cast<int>(GetSize<typename config::input>::value) 
            <= static_cast<int>(position),
        AppendItem<InputBlank, typename config::input>,
        Identity<typename config::input>>::type::type input;
    typedef typename config::state state;

    typedef config end_config;
    typedef input end_input;
    typedef state end_state;
    enum { end_position = position };
};

template<typename Input, typename Transitions, typename StartState>
struct TuringMachine {
    typedef Input input;
    typedef Transitions transitions;
    typedef StartState start_state;

    typedef Controller<Configuration<Input, StartState, 0>, Transitions> controller;
    typedef typename controller::end_config end_config;
    typedef typename controller::end_input end_input;
    typedef typename controller::end_state end_state;
    enum { end_position = controller::end_position };
};

#include <ostream>

template<>
char const* Input<-1>::name = "_";

char const* QAccept::name = "qaccept";
char const* QReject::name = "qreject";

int main() {
    DEF_INPUT(1, x);
    DEF_INPUT(2, x_mark);
    DEF_INPUT(3, split);

    DEF_STATE(0, start);
    DEF_STATE(1, find_blank);
    DEF_STATE(2, go_back);

    /* syntax:  State, Input, NewState, Output, Move */
    typedef TypeList< 
        Rule<start, x, find_blank, x_mark, Right>,
        Rule<find_blank, x, find_blank, x, Right>,
        Rule<find_blank, split, find_blank, split, Right>,
        Rule<find_blank, InputBlank, go_back, x, Left>,
        Rule<go_back, x, go_back, x, Left>,
        Rule<go_back, split, go_back, split, Left>,
        Rule<go_back, x_mark, start, x, Right>,
        Rule<start, split, QAccept, split, Left>> rules;

    /* syntax: initial input, rules, start state */
    typedef TuringMachine<TypeList<x, x, x, x, split>, rules, start> double_it;
    static_assert(IsSame<double_it::end_input, 
                         TypeList<x, x, x, x, split, x, x, x, x>>::value, 
                "Hmm... This is borky!");
}

131
आपके पास अपने हाथों पर बहुत अधिक समय है।
मार्क केगेल

2
यह उन सभी कोष्ठकों की जगह एक प्रमाणित शब्द को छोड़कर लिस्प की तरह दिखता है।
साइमन कुआंग

1
पूर्ण स्रोत सार्वजनिक रूप से कहीं भी उपलब्ध है, जिज्ञासु पाठक के लिए? :)
OJFord

1
बस प्रयास अधिक श्रेय का मार्ग प्रशस्त करता है :-) यह कोड संकलित करता है (gcc-4.9) लेकिन कोई आउटपुट नहीं देता है - ब्लॉग पोस्ट की तरह थोड़ी अधिक जानकारी, बहुत अच्छा होगा।
अल्फ्रेड ब्रेटेरड

2
@ ओलीफ़ॉर्ड मैं इसका एक संस्करण पास्टबिन पेज पर पाया गया और इसे यहाँ पुन : पेश किया : coliru.stacked-crooked.com/a/de06f2f63f905b7e
जोहान्स शाउब - ११:०५ पर

31

" C ++ टेम्प्लेट्स ट्यूरिंग कंप्लीट हैं " टेंपरिंग में ट्यूरिंग मशीन का क्रियान्वयन देता है ... जो कि गैर-तुच्छ है और इस बिंदु को बहुत ही प्रत्यक्ष तरीके से साबित करता है। बेशक, यह भी बहुत उपयोगी नहीं है!



13

मेरा सी ++ थोड़ा कठोर है, इसलिए यह सही नहीं हो सकता है, लेकिन यह करीब है।

template <int N> struct Factorial
{
    enum { val = Factorial<N-1>::val * N };
};

template <> struct Factorial<0>
{
    enum { val = 1 };
}

const int num = Factorial<10>::val;    // num set to 10! at compile time.

बिंदु यह प्रदर्शित करना है कि कंपाइलर पूरी तरह से पुनरावर्ती परिभाषा का मूल्यांकन कर रहा है जब तक कि वह एक उत्तर तक नहीं पहुंचता।


1
उम्म ... आपको टेम्पलेट विशेषज्ञता के संकेत देने के लिए संरचना तथ्य <0> से पहले लाइन पर "टेम्पलेट <>" की आवश्यकता नहीं है?
paxos1977 22

11

एक गैर-तुच्छ उदाहरण देने के लिए: http://gitorious.org/metatrace , एक C ++ संकलन समय किरण अनुरेखक।

ध्यान दें कि C ++ 0x एक गैर-टेम्पलेट, संकलन-समय, ट्यूरिंग-पूर्ण सुविधा को इस रूप में जोड़ेगा constexpr:

constexpr unsigned int fac (unsigned int u) {
        return (u<=1) ? (1) : (u*fac(u-1));
}

आप constexprहर जगह जहाँ आप समय संकलन की जरूरत है, -प्रचार का उपयोग कर सकते हैं , लेकिन आप constexprगैर-कास्ट मापदंडों के साथ -functions भी कॉल कर सकते हैं ।

एक शांत बात यह है कि यह अंत में संकलन समय फ़्लोटिंग पॉइंट गणित को सक्षम करेगा, हालांकि मानक स्पष्ट रूप से कहता है कि समय फ़्लोटिंग पॉइंट अंकगणित को रनटाइम फ़्लोटिंग पॉइंट अंकगणित से मेल नहीं खाना है:

bool f(){
    char array[1+int(1+0.2-0.1-0.1)]; //Must be evaluated during translation
    int  size=1+int(1+0.2-0.1-0.1); //May be evaluated at runtime
    return sizeof(array)==size;
}

यह अनिर्दिष्ट है कि क्या च () का मूल्य सही या गलत होगा।


8

बुक मॉडर्न C ++ डिज़ाइन - आंद्रेई अलेक्जेंड्रेस्कु द्वारा जेनेरिक प्रोग्रामिंग और डिज़ाइन पैटर्न उपयोगी और शक्तिशाली जेनेरिक प्रोग्रामिंग पैटर्न के साथ अनुभव प्राप्त करने के लिए सबसे अच्छी जगह है।


8

फैक्टोरियल उदाहरण वास्तव में यह नहीं दिखाता है कि टेम्परिंग पूर्ण हो रही है, जितना कि यह दर्शाता है कि वे आदिम पुनरावृत्ति का समर्थन करते हैं। यह दिखाने का सबसे आसान तरीका है कि टेम्प्लेट पूर्ण रूप से ट्यूरिंग हैं, यह चर्च-ट्यूरिंग थीसिस द्वारा है, जो कि ट्यूरिंग मशीन (गन्दा और थोड़ा व्यर्थ) या तीन नियमों (ऐप, एब्स वेर) को लागू करने से है। उत्तरार्द्ध बहुत सरल है और कहीं अधिक दिलचस्प है।

जिस पर चर्चा की जा रही है वह एक अत्यंत उपयोगी विशेषता है जब आप समझते हैं कि C ++ टेम्पलेट संकलन के समय शुद्ध कार्यात्मक प्रोग्रामिंग की अनुमति देता है, एक औपचारिकता जो अभिव्यंजक, शक्तिशाली और सुरुचिपूर्ण है, लेकिन यह लिखने के लिए बहुत जटिल है कि आपके पास बहुत कम अनुभव है। यह भी देखें कि कितने लोगों को लगता है कि सिर्फ भारी टेम्पलेटेड कोड प्राप्त करने के लिए अक्सर एक बड़े प्रयास की आवश्यकता हो सकती है: यह वास्तव में (शुद्ध) कार्यात्मक भाषाओं के साथ मामला है, जो कठिन लेकिन आश्चर्यजनक रूप से उपज कोड बनाता है जिसमें डीबगिंग की आवश्यकता नहीं होती है।


अरे, आप किन तीन नियमों का उल्लेख करते हैं, मुझे आश्चर्य है, "ऐप, एब्स, var" द्वारा? मुझे लगता है कि पहले दो क्रमशः फंक्शन एप्लीकेशन और एब्सट्रैक्शन (लैम्ब्डा डेफिनिशन (?)) हैं। ऐसा क्या? और तीसरा कौन सा है? चर के साथ कुछ करना है?
विसेक

मुझे व्यक्तिगत रूप से लगता है कि यह आम तौर पर संकलक में भाषा समर्थन में आदिम पुनरावृत्ति की तुलना में बेहतर होगा, यह ट्यूरिंग पूर्ण होने के बाद से, एक भाषा के लिए एक संकलक जो संकलन-समय का समर्थन करता है आदिम पुनर्संयोजन गारंटी दे सकता है कि कोई भी निर्माण पूर्ण या विफल होगा, लेकिन जिसकी निर्माण प्रक्रिया ट्यूरिंग कम्प्लीट नहीं है, वह कृत्रिम रूप से बिल्ड को बाधित करने के अलावा, इसलिए यह ट्यूरिंग कम्प्लीट नहीं है।
सुपरकैट

5

मुझे लगता है कि इसे टेम्प्लेट मेटा-प्रोग्रामिंग कहा जाता है


2
यह इसका उपयोगी पक्ष है। नकारात्मक पक्ष यह है कि मुझे ज्यादातर लोगों पर संदेह है (और निश्चित रूप से मुझे नहीं) वास्तव में उस सामान में से जो भी चल रहा है उसका एक छोटा प्रतिशत भी कभी भी समझ जाएगा। यह भयानक रूप से अपठनीय, अचूक सामान है।
माइकल बूर

3
मुझे लगता है कि यह पूरी C ++ भाषा का दोष है। यह एक राक्षस बन रहा है ...
फेडरिको ए। रामपोनी

C ++ 0x इसे बहुत आसान बनाने का वादा कर रहा है (और मेरे अनुभव में, सबसे बड़ा मुद्दा यह है कि कंपाइलर इसका पूरी तरह से समर्थन नहीं करते हैं, जो C ++ 0x मदद नहीं करेगा)। विशेष रूप से अवधारणाओं को देखने से लगता है कि वे चीजों को साफ कर देंगे, जैसे कि बहुत सारे SFINAE सामानों से छुटकारा पाना, जिन्हें पढ़ना मुश्किल है।
सहसंबंध

@MichaelBurr C ++ समिति अपठनीय, अचूक सामान की परवाह नहीं करती है; वे सिर्फ सुविधाएँ जोड़ना पसंद करते हैं।
Sapphire_Brick

4

ठीक है, यहां 4-स्टेट 2-सिंबल बिजी बीवर चल रहे ट्यूरिंग मशीन कार्यान्वयन का संकलन समय है

#include <iostream>

#pragma mark - Tape

constexpr int Blank = -1;

template<int... xs>
class Tape {
public:
    using type = Tape<xs...>;
    constexpr static int length = sizeof...(xs);
};

#pragma mark - Print

template<class T>
void print(T);

template<>
void print(Tape<>) {
    std::cout << std::endl;
}

template<int x, int... xs>
void print(Tape<x, xs...>) {
    if (x == Blank) {
        std::cout << "_ ";
    } else {
        std::cout << x << " ";
    }
    print(Tape<xs...>());
}

#pragma mark - Concatenate

template<class, class>
class Concatenate;

template<int... xs, int... ys>
class Concatenate<Tape<xs...>, Tape<ys...>> {
public:
    using type = Tape<xs..., ys...>;
};

#pragma mark - Invert

template<class>
class Invert;

template<>
class Invert<Tape<>> {
public:
    using type = Tape<>;
};

template<int x, int... xs>
class Invert<Tape<x, xs...>> {
public:
    using type = typename Concatenate<
        typename Invert<Tape<xs...>>::type,
        Tape<x>
    >::type;
};

#pragma mark - Read

template<int, class>
class Read;

template<int n, int x, int... xs>
class Read<n, Tape<x, xs...>> {
public:
    using type = typename std::conditional<
        (n == 0),
        std::integral_constant<int, x>,
        Read<n - 1, Tape<xs...>>
    >::type::type;
};

#pragma mark - N first and N last

template<int, class>
class NLast;

template<int n, int x, int... xs>
class NLast<n, Tape<x, xs...>> {
public:
    using type = typename std::conditional<
        (n == sizeof...(xs)),
        Tape<xs...>,
        NLast<n, Tape<xs...>>
    >::type::type;
};

template<int, class>
class NFirst;

template<int n, int... xs>
class NFirst<n, Tape<xs...>> {
public:
    using type = typename Invert<
        typename NLast<
            n, typename Invert<Tape<xs...>>::type
        >::type
    >::type;
};

#pragma mark - Write

template<int, int, class>
class Write;

template<int pos, int x, int... xs>
class Write<pos, x, Tape<xs...>> {
public:
    using type = typename Concatenate<
        typename Concatenate<
            typename NFirst<pos, Tape<xs...>>::type,
            Tape<x>
        >::type,
        typename NLast<(sizeof...(xs) - pos - 1), Tape<xs...>>::type
    >::type;
};

#pragma mark - Move

template<int, class>
class Hold;

template<int pos, int... xs>
class Hold<pos, Tape<xs...>> {
public:
    constexpr static int position = pos;
    using tape = Tape<xs...>;
};

template<int, class>
class Left;

template<int pos, int... xs>
class Left<pos, Tape<xs...>> {
public:
    constexpr static int position = typename std::conditional<
        (pos > 0),
        std::integral_constant<int, pos - 1>,
        std::integral_constant<int, 0>
    >::type();

    using tape = typename std::conditional<
        (pos > 0),
        Tape<xs...>,
        Tape<Blank, xs...>
    >::type;
};

template<int, class>
class Right;

template<int pos, int... xs>
class Right<pos, Tape<xs...>> {
public:
    constexpr static int position = pos + 1;

    using tape = typename std::conditional<
        (pos < sizeof...(xs) - 1),
        Tape<xs...>,
        Tape<xs..., Blank>
    >::type;
};

#pragma mark - States

template <int>
class Stop {
public:
    constexpr static int write = -1;
    template<int pos, class tape> using move = Hold<pos, tape>;
    template<int x> using next = Stop<x>;
};

#define ADD_STATE(_state_)      \
template<int>                   \
class _state_ { };

#define ADD_RULE(_state_, _read_, _write_, _move_, _next_)          \
template<>                                                          \
class _state_<_read_> {                                             \
public:                                                             \
    constexpr static int write = _write_;                           \
    template<int pos, class tape> using move = _move_<pos, tape>;   \
    template<int x> using next = _next_<x>;                         \
};

#pragma mark - Machine

template<template<int> class, int, class>
class Machine;

template<template<int> class State, int pos, int... xs>
class Machine<State, pos, Tape<xs...>> {
    constexpr static int symbol = typename Read<pos, Tape<xs...>>::type();
    using state = State<symbol>;

    template<int x>
    using nextState = typename State<symbol>::template next<x>;

    using modifiedTape = typename Write<pos, state::write, Tape<xs...>>::type;
    using move = typename state::template move<pos, modifiedTape>;

    constexpr static int nextPos = move::position;
    using nextTape = typename move::tape;

public:
    using step = Machine<nextState, nextPos, nextTape>;
};

#pragma mark - Run

template<class>
class Run;

template<template<int> class State, int pos, int... xs>
class Run<Machine<State, pos, Tape<xs...>>> {
    using step = typename Machine<State, pos, Tape<xs...>>::step;

public:
    using type = typename std::conditional<
        std::is_same<State<0>, Stop<0>>::value,
        Tape<xs...>,
        Run<step>
    >::type::type;
};

ADD_STATE(A);
ADD_STATE(B);
ADD_STATE(C);
ADD_STATE(D);

ADD_RULE(A, Blank, 1, Right, B);
ADD_RULE(A, 1, 1, Left, B);

ADD_RULE(B, Blank, 1, Left, A);
ADD_RULE(B, 1, Blank, Left, C);

ADD_RULE(C, Blank, 1, Right, Stop);
ADD_RULE(C, 1, 1, Left, D);

ADD_RULE(D, Blank, 1, Right, D);
ADD_RULE(D, 1, Blank, Right, A);

using tape = Tape<Blank>;
using machine = Machine<A, 0, tape>;
using result = Run<machine>::type;

int main() {
    print(result());
    return 0;
}

Ideone proof run: https://ideone.com/MvBU3Z

स्पष्टीकरण: http://victorkomarov.blogspot.ru/2016/03/compile-time-turing-machin.html

Github अधिक उदाहरणों के साथ: https://github.com/fnz/CTTM


3

आप इस आलेख को डॉ। डॉब्स से एफएफटी कार्यान्वयन पर उन टेम्प्लेट के साथ देख सकते हैं जो मुझे लगता है कि यह तुच्छ नहीं है। मुख्य बिंदु गैर संकलक कार्यान्वयन की तुलना में संकलक को बेहतर अनुकूलन करने की अनुमति देना है क्योंकि FFT एल्गोरिथ्म बहुत सारे स्थिरांक (उदाहरण के लिए पाप तालिकाओं) का उपयोग करता है

भाग I

भाग द्वितीय


2

यह इंगित करने के लिए भी मजेदार है कि यह एक शुद्ध रूप से कार्यात्मक भाषा है, जिसमें डिबग करना लगभग असंभव है। यदि आप जेम्स पोस्ट को देखते हैं तो आप देखेंगे कि मेरे लिए इसका मतलब कार्यात्मक है। सामान्य तौर पर यह C ++ की सबसे उपयोगी विशेषता नहीं है। यह ऐसा करने के लिए डिज़ाइन नहीं किया गया था। यह कुछ ऐसा है जिसे खोजा गया था।



1

एक उदाहरण जो यथोचित उपयोगी है, एक अनुपात वर्ग है। वहाँ कुछ वेरिएंट के आसपास चल रहे हैं। आंशिक अधिभार के साथ D == 0 केस पकड़ना काफी सरल है। वास्तविक कंप्यूटिंग एन और डी के जीसीडी की गणना और संकलन समय है। यह आवश्यक है जब आप संकलन-समय की गणना में इन अनुपातों का उपयोग कर रहे हों।

उदाहरण: जब आप सेंटीमीटर (5) * किलोमीटर (5) की गणना कर रहे हों, तो संकलन के समय आप का अनुपात कई गुना बढ़ जाएगा <1,100> और अनुपात <1000,1>। ओवरफ्लो को रोकने के लिए, आप <1000,100> के अनुपात के बजाय एक अनुपात <10,1> चाहते हैं।


0

एक ट्यूरिंग मशीन ट्यूरिंग-पूर्ण है, लेकिन इसका मतलब यह नहीं है कि आप उत्पादन कोड के लिए एक का उपयोग करना चाहते चाहिए।

टेम्पलेट्स के साथ कुछ भी गैर-तुच्छ करने की कोशिश करना मेरे अनुभव में गड़बड़, बदसूरत और व्यर्थ है। आपके पास "अपना" कोड "डीबग" करने का कोई तरीका नहीं है, संकलन-समय त्रुटि संदेश गुप्त और आमतौर पर सबसे अधिक संभावना वाली जगहों पर होगा, और आप अलग-अलग तरीकों से समान प्रदर्शन लाभ प्राप्त कर सकते हैं। (संकेत: ४! = २४)। इससे भी बदतर, आपका कोड औसत C ++ प्रोग्रामर के लिए समझ से बाहर है, और वर्तमान संकलक के भीतर समर्थन के व्यापक स्तर के कारण गैर-पोर्टेबल होने की संभावना होगी।

जेनेरिक कोड जेनरेशन (कंटेनर क्लासेस, क्लास रैपर, मिक्स-इन) के लिए टेम्प्लेट बहुत बढ़िया हैं, लेकिन नहीं - मेरी राय में टेम्परिंग का पूरा ट्यूरेंस प्रयोग में नहीं है


4! 24 हो सकता है, लेकिन MY_FAVORITE_MACRO_VALUE क्या है! ? ठीक है, मुझे नहीं लगता कि यह एक अच्छा विचार है।
बजे जेफरी एल व्हाइटलेज

0

कैसे नहीं कार्यक्रम का एक और उदाहरण:

टेम्पलेट <int गहराई, इंट ए, टाइपनेम बी>
संरचना K17 {
    static const int x =
    K17 <गहराई + 1, 0, K17 <गहराई, ए, बी>> :: x
    + K17 <गहराई + 1, 1, K17 <गहराई, ए, बी>> :: x
    + K17 <गहराई + 1, 2, K17 <गहराई, ए, बी>> :: x
    + K17 <गहराई + 1, 3, K17 <गहराई, ए, बी>> :: x
    + के 17 <गहराई + 1, 4, के 17 <गहराई, ए, बी>> :: एक्स;
};
टेम्पलेट <int A, टाइपनाम बी>
संरचना K17 <16, A, B> {स्थिर कास्ट int x = 1; };
स्थिर const int z = K17 <0,0, int> :: x;
शून्य मुख्य (शून्य) {}

C ++ टेम्पलेट पर पोस्ट पूर्ण रूप से ट्यूरिंग कर रहे हैं


जिज्ञासु के लिए, x का उत्तर pow (5,17-गहराई) है;
जूल

यह देखने के लिए बहुत सरल है कि जब आप महसूस करते हैं कि टेम्पलेट तर्क ए और बी कुछ नहीं करते हैं और उन्हें हटाते हैं, और फिर इसके अलावा सभी को बदलें K17<Depth+1>::x * 5
डेविड स्टोन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.