2016-08-04 28 views
0

と私は種類、文字列で定義された各のツリー階層を持って、このような何か:型階層、コンパイル型チェック

com 
com.example 
com.example.shape 
com.example.shape.triangle 
com.example.shape.triangle.equilateral 
com.example.shape.triangle.isosceles 
com.example.shape.triangle.right 
com.example.shape.quadrilateral 
com.example.shape.quadrilateral.rectangle 
com.example.shape.quadrilateral.squere 

タイプに変更することができる動的パラメータ、といくつかのデータを定義しますコンパイル時の型階層を作成する方法はありません。つまり、すべてのエンティティは型名(文字列)とパラメータリストに過ぎず、システムに新しい型を登録することができます。それにもかかわらず、多くの種類があらかじめ定義されており、システムの起動時に登録することができます。実行時に作成され、事前定義されたデータで同じ経験を得るために、私はこの動的表現を両方に使用します。あらかじめ定義された型については、コンパイル時に型名を検証できるメカニズムがありたいと思います。使用する必要があるたびに文字列を直接コードに入れたくない場合は、文字列const式を定義することで解決できますが、次のようなものではありません。

string some_type = "com.example.type1"; 
... 
registerType(some_type, parameters_definition); 

私はより良い方法を考えています。

別のアプローチは、このようなものにすることです:

#include <iostream> 
#include <string> 

struct Base { 
    Base(std::string parent_name, std::string my_name) : name_(parent_name + "." + my_name) {} 
    std::string name_; 
}; 

std::ostream& operator<< (std::ostream& os, const Base& base) { 
    os << base.name_; 
    return os; 
} 

struct G : Base { 
    G(std::string parent_name, std::string my_name) : Base(parent_name, my_name) {} 
}; 

struct F : Base { 
    F(std::string parent_name, std::string my_name) : Base(parent_name, my_name) {} 
    G rectangle{name_, "rectangle"}; 
    G squere{name_, "squere"}; 
}; 

struct E : Base { 
    E(std::string parent_name, std::string my_name) : Base(parent_name, my_name) {} 
}; 

struct D : Base{ 
    D(std::string parent_name, std::string my_name) : Base(parent_name, my_name) {} 
    E equilateral{name_, "equilateral"}; 
    E isosceles{name_, "isosceles"}; 
    E right{name_, "right"}; 
}; 

struct C : Base { 
    C(std::string parent_name, std::string my_name) : Base(parent_name, my_name) {} 
    D triangle{name_, "triangle"}; 
    F quadrilateral{name_, "quadrilateral"}; 
}; 

struct B : Base{ 
    B(std::string parent_name, std::string my_name) : Base(parent_name, my_name) {} 
    C shape{name_, "shape"}; 
}; 

struct A { 
    A(std::string my_name) : name_(my_name) {}; 
    std::string name_; 
    B example{name_, "example"}; 
}; 

std::ostream& operator<< (std::ostream& os, const A& a) { 
    os << a.name_; 
    return os; 
} 


int main() { 

    A com("com"); 

    std::cout << com << std::endl; 
    std::cout << com.example << std::endl; 
    std::cout << com.example.shape << std::endl; 
    std::cout << com.example.shape.triangle << std::endl; 
    std::cout << com.example.shape.triangle.equilateral << std::endl; 
    std::cout << com.example.shape.triangle.isosceles << std::endl; 
    std::cout << com.example.shape.triangle.right << std::endl; 
    std::cout << com.example.shape.quadrilateral << std::endl; 
    std::cout << com.example.shape.quadrilateral.rectangle << std::endl; 
    std::cout << com.example.shape.quadrilateral.squere << std::endl; 

    return 0; 
} 

特にコードヒントとIDEを持つ、使用することがいいですが、残念ながら簡単ではない定義します。ツリーレベルごとに、新しいクラスを新しいメンバーで定義する必要があります。その名前はいくつかの文字列に対応しています。

私はより良い解決策を探しています - より簡単です。何らかのテンプレートの特殊化のように定義するのは素晴らしいことですが、どうやってそれを行うのか分かりません。

何か提案歓迎:) よろしく、 Piciu。

+1

これは、文字列を印刷するだけの複雑な方法ではないと推測します。実際にこの命名階層は何ですか?それはあなたがそれを見るようにソリューションの非常に特定の部分であなたの試みを参照してくださいではなく、基礎となる問題をよりよく理解するのに役立ちます – Smeeheey

答えて

0

これはやや異なるアプローチです。

ここでは、comの名前に一致する変数name_tokenが作成されます。私たちはスマートと一緒にそれらをsticth operator/

あり定型のビットが最初であるが、実際の文法は簡潔である:

template<class...Ts> 
struct or_trait : std::false_type {}; 
template<class T0, class...Ts> 
struct or_trait<T0, Ts...> : std::integral_constant<bool, T0{} || or_trait<Ts...>{} > {}; 

    namespace names { 
    template<class Tag, bool is_root, class...Parents> 
    struct name_token { 
     std::string name; 
     name_token(std::string in):name(std::move(in)) {} 

     template<class Rhs> 
     constexpr static bool is_valid() { 
     return or_trait< std::is_same<Parents, Rhs>... >{}; 
     } 
    }; 

    template<class Tag, class...Parents> 
    name_token<Tag, false, Parents...> name(Tag, std::string s, Parents const&...) { return std::move(s); } 

    template<class Tag, class...Parents> 
    struct name_token<Tag, true, Parents...> { 
     std::string name; 
     name_token(std::string in):name(std::move(in)) {} 

     operator std::string() const { return name; } 

     template<class Rhs> 
     constexpr static bool is_valid() { 
     return or_trait< std::is_same<Parents, Rhs>... >{}; 
     } 
     friend std::ostream& operator<<(std::ostream& os, name_token const& self) { 
     return os << std::string(self); 
     } 
    }; 

    template<class Tag, class...Parents> 
    name_token<Tag, true, Parents...> rootname(Tag, std::string s, Parents const&...) { return std::move(s); } 


    template<class LastToken> 
    struct name_expression { 
     std::string current; 
     operator std::string()const { return current; } 

     friend std::ostream& operator<<(std::ostream& os, name_expression const& self) { 
     return os << std::string(self); 
     } 

     template<class Rhs> 
     constexpr static bool is_valid() { 
     return LastToken::template is_valid<Rhs>(); 
     } 
    }; 

    template<class Lhs, class Rhs, 
     std::enable_if_t< Rhs::template is_valid<Lhs>(), int>* =nullptr 
    > 
    auto operator/(Lhs lhs, Rhs rhs) { 
     return name_expression<Rhs>{ std::string(lhs) + "." + rhs.name }; 
    } 

    template<class Lhs, class Rhs, 
     std::enable_if_t< Rhs::template is_valid<Lhs>(), int>* =nullptr 
    > 
    auto operator/(name_expression<Lhs> lhs, Rhs rhs) { 
     return name_expression<Rhs>{ std::string(lhs) + "." + rhs.name }; 
    } 

    template<class Tag, class Token> 
    struct uniquely_tagged { 
     Tag tag; 
     Token const& token; 
     auto operator*(std::string n)&& { 
      return name(tag, std::move(n), token); 
     } 
    }; 
    template<class OldTag, bool b, class...Parents, class Tag> 
    auto operator*(name_token<OldTag, b,Parents...> const& parent, Tag tag) { 
     return uniquely_tagged<Tag, name_token<OldTag, b,Parents...>>{tag, parent}; 
    } 
    } 

次のように我々は、名前のトークンを作成することができます。今すぐcom/example作品を

auto com = names::rootname([]{}, "com"); 
auto example = com*[]{}*"example"; 
auto shape = example*[]{}*"shape"; 
auto triangle = shape*[]{}*"triangle"; 
auto right = triangle*[]{}*"right"; 
auto isosceles = triangle*[]{}*"isosceles"; 
auto equilateral = triangle*[]{}*"equilateral"; 


auto quadrilateral = shape*[]{}*"quadrilateral"; 
auto rectangle = quadrilateral*[]{}*"rectangle"; 
auto square = quadrilateral*[]{}*"square"; 

を、しかしcom/shapeが生成しますコンパイル時エラー。

Live example

ビット醜い、これを使用しないでください。

+0

こんにちは、本当にいいね。使用するのはちょっと難しいです(メンバーのようなIDEのサポートはありません)。このコードを書くことで時間が短縮され、それを理解することができたことは驚きです:) – Piciu

関連する問題