Created
January 11, 2020 15:12
-
-
Save Nekrolm/8e8dd870b1b600be1adbd5429f96551d to your computer and use it in GitHub Desktop.
c++20 concepts example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <type_traits> | |
template <class From, class To> | |
concept is_convertible = requires(From f){ | |
{ static_cast<To>(f) } -> To; | |
}; | |
template <typename Fst> | |
concept BaseFst = requires { | |
typename Fst::Arc; | |
typename Fst::StateId; | |
} && requires(Fst fst, typename Fst::StateId s) { | |
{ fst.Start() } -> typename Fst::StateId; | |
{ fst.Final(s)}; | |
}; | |
template <class Fst> | |
concept ExpandedFst = BaseFst<Fst> && | |
requires(Fst fst, | |
typename Fst::StateId s) { | |
{ fst.NumStates() } -> is_convertible<std::size_t>; | |
{ fst.NumArcs(s) } -> is_convertible<std::size_t>; | |
}; | |
template <class AIter, class Fst> | |
concept ArcIterator = BaseFst<Fst> && requires(AIter iter, | |
Fst fst, | |
typename Fst::StateId s) { | |
{ iter.Done() } -> bool; | |
{ iter.Value() } -> is_convertible<typename Fst::Arc>; | |
{ iter.Next() }; | |
{ AIter(fst, s) }; | |
}; | |
template <class SIter, class Fst> | |
concept StateIterator = BaseFst<Fst> && requires(SIter iter, | |
Fst fst) { | |
{ iter.Done() } -> bool; | |
{ iter.Value() } -> is_convertible<typename Fst::StateId>; | |
{ iter.Next() }; | |
{ SIter(fst) }; | |
}; | |
template <class Fst> | |
concept IterableFst = BaseFst<Fst> && | |
requires{ | |
typename Fst::ArcIterator; | |
typename Fst::StateIterator; | |
} | |
&& ArcIterator<typename Fst::ArcIterator, Fst> | |
&& StateIterator<typename Fst::StateIterator, Fst>; | |
//---------------------- | |
//---------------------- | |
// ---- TEST ----------- | |
template <BaseFst FstT> | |
struct AIterTpl { | |
AIterTpl(const FstT&, typename FstT::StateId s); // ctor; | |
const typename FstT::Arc& Value(); | |
void Next(); | |
bool Done(); | |
}; | |
template <BaseFst FstT> | |
struct SIterTpl { | |
SIterTpl(const FstT&); // ctor; | |
int Value(); | |
void Next(); | |
bool Done(); | |
}; | |
class VectorFst { | |
public: | |
struct Arc { | |
int nextstate; | |
}; | |
using StateId = int; | |
StateId Start() { return 0; }; | |
float Final(StateId) {return 0; }; | |
int NumStates() {return 0;}; | |
int NumArcs(StateId s) {return 0;}; | |
// forward declaration | |
// we cannot use S/AIterTpl here due to concept constraint: | |
// VectorFst must be a complete type before conceps checking; | |
// so definition is placed outside. | |
struct ArcIterator; | |
struct StateIterator; | |
}; | |
struct VectorFst::ArcIterator : AIterTpl<VectorFst> | |
{ using AIterTpl<VectorFst>::AIterTpl; }; | |
struct VectorFst::StateIterator : SIterTpl<VectorFst> | |
{ using SIterTpl<VectorFst>::SIterTpl; }; | |
template <class Fst> requires BaseFst<Fst> | |
void check_base(const Fst& fst){} | |
template <class Fst> requires ExpandedFst<Fst> | |
void check_expanded(const Fst& fst){} | |
template <class Fst> requires IterableFst<Fst> | |
void check_iterable(const Fst& fst){} | |
class NotFst { | |
public: | |
}; | |
int main() { | |
VectorFst fst; | |
NotFst nfst; | |
check_base(fst); | |
check_expanded(fst); | |
check_iterable(fst); | |
// check(nfst); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment