2017-01-19 1 views
3

Ich mag Makros verwenden, um meinen Quellcode zu erstellen einfache

Dies ist mein CodeWie kann ich einen neuen Stil zum Erstellen von Schleifen erstellen?

constexpr auto make_index_sequence_array(size_t i ,std::index_sequence<arg...>) { 
    return std::array<size_t, sizeof...(arg)> {i+arg...}; 
} 
#define RANGE(start , end) make_index_sequence_array(start,std::make_index_sequence<end-start>{}) 
#define ZeroTo(end) RANGE(0 , end) 
#define Repeat(end) for(auto itr : RANGE(0 , end)) 

void main() { 
    vector<int> a = { 1,2,3 }; 
    for (auto row : RANGE(0,a.size())) 
     cout << std::setw(4) << a[row]; 
    cout << '\n'; 
} 

Ich weiß, dass ich verwenden kann:

void main() { 
    vector<int> a = { 1,2,3 }; 
    for (auto itr: a) 
     cout << std::setw(4) << itr; 
    cout << '\n'; 
} 

Aber es ist ein einfaches Beispiel, und ich möchte Verwenden Sie diesen Stil in mehreren Situationen. Der Fehler beim Kompilieren ist:

Fehler C2975 '_Size': ungültiges Template-Argument für 'std :: make_index_sequence', erwartete Kompilierung-Konstante Ausdruck

Wie kann ich mein Makros verwenden? Oder ist es überhaupt möglich?

+5

Meine starke Meinung folgt: Verwenden von Makros, um den Quellcode kürzer zu machen, ist eine sehr schlechte Idee. Es verbirgt Dinge, die Sie sehen wollen und macht das Finden von Fehlern zu einem echten Schmerz im Hintern. Makros haben Verwendung, aber das ist nicht gut. –

+0

Eigentlich möchte ich es einfacher machen –

+0

Für diesen speziellen Fall könnten Sie 'für (automatische Zeile: boost :: irange (0, a.size()))' –

Antwort

2

Meine Empfehlung ist, dass Sie Iteratoren verwenden, schrieb ich ein Beispiel unten. So etwas wie dies tun würde, es in C++ < C++ 17:

#include <iostream> 

template <class T> 
struct RangeIter { 
    RangeIter(T from, T to, T curr) : 
    _from(from), _to(to), _curr(curr) { 
    } 

    T operator*() const { 
     return _curr; 
    } 

    T operator++() { 
     ++_curr; 
     return _curr; 
    } 

    bool operator==(const RangeIter & other) { 
     assert(_from == other._from && _to == other._to); 
     return _curr == other._curr; 
    } 

    bool operator!=(const RangeIter & other) { 
     return !(_curr == other._curr); 
    } 
    T _from, _to, _curr; 
    }; 

template <class T> 
struct Range { 
    Range(T from, T to) : _from(from), _to(to) {} 

    RangeIter<T> begin() { return RangeIter<T>(_from, _to, _from); } 
    RangeIter<T> end() { 
    return RangeIter<T>(_from, _to, _to); 
    } 

    T _from, _to; 
}; 

template <class T> 
Range<T> makeRange(T to, T from) { 
    return Range<T>(to, from); 
} 

int main() { 

    for (auto i : makeRange(0, 10)) { 
     std::cout << i << std::endl; 
    } 
} 

Für C 17 ++ Sie verschiedene Typen für den Beginn und das Ende Iterator und verbessern auf diese nutzen können. Sie können Sentinels verwenden. Sie könnten einen Blick hier: How the new range-based for loop in C++17 helps Ranges TS?

A C++ - 17 einzige Lösung hier:

#include <iostream> 


template <class T> 
struct RangeSentinel { 
    RangeSentinel(T stopVal) : _stopVal(stopVal) {} 

    T _stopVal; 
}; 

template <class T> 
struct RangeIter { 
    RangeIter(T from, T to, T curr) : 
    _from(from), _to(to), _curr(curr) { 
    } 

    T operator*() const { 
     return _curr; 
    } 

    T operator++() { 
     ++_curr; 
     return _curr; 
    } 

    bool operator==(const RangeSentinel<T> & other) { 
     assert(_from == other._from && _to == other._to); 
     return _curr == other._stopVal; 
    } 

    bool operator!=(const RangeSentinel<T> & other) { 
     return !(_curr == other._stopVal); 
    } 
    T _from, _to, _curr; 
    }; 



template <class T> 
struct Range { 
    Range(T from, T to) : _from(from), _to(to) {} 

    RangeIter<T> begin() { return RangeIter<T>(_from, _to, _from); } 
    RangeSentinel<T> end() { 
    return RangeSentinel<T>(_to); 
    } 

    T _from, _to; 
}; 

template <class T> 
Range<T> makeRange(T to, T from) { 
    return Range<T>(to, from); 
} 

int main() { 

    for (auto i : makeRange(0, 10)) { 
     std::cout << i << std::endl; 
    } 
} 

Wie Sie sehen können, in der C++ 17-Lösung Ich brauche nicht noch einmal speichern _From und _to Variablen , da der Sentinel ein anderer Typ ist.

+0

überprüfen Sie Code für int main() { \t für (auto i: makerange (2, 11)) { \t \t std :: cout << i << std :: endl; \t} \t getchar(); } Es funktioniert nicht richtig. –

+1

Danke @SamMokari für die Rückmeldung. Ich denke, das ändert nichts an dem, was ich darzustellen versuche. Ich mache keine Hausaufgaben, ich gebe Anweisungen. :) Ich denke du könntest es von da an vernünftig anpassen. –

Verwandte Themen