2016-05-30 6 views
3

深いC++ 11バリデーションテンプレートの魔法の使用法を持つコードがあります。私はテンプレートツリーの一部を特定するために特殊なクラスを使用しています。これは "タグ"という名前です。各タグには固有の番号識別子があります。私はここでは、タグの識別子に部分型の知識を持つテンプレートの引数にアクセスする

にアクセスする方法を方法を見つける必要がある は、いくつかの小さな例です。

#include <string> 
#include <iostream> 

template <unsigned long ID, typename PARAM> 
class tag_ 
{ 
    //getter for ID. Better to exclude it. If possible - move to external helper 
    constexpr static unsigned long get_id() {return ID;} 
    //PARAM is used in some functions of this class 
}; 

//tag's declarations for future usage 
template<typename PARAM> 
using tag1 = tag_<1UL, PARAM>; 
template<typename PARAM> 
using tag2 = tag_<2UL, PARAM>; 
template<typename PARAM> 
using tag3 = tag_<3UL, PARAM>; 

//helper class that can iterate TAGS 
template <template<typename> class... TAGS> 
struct helper 
{}; 
template <template<typename> class TAG> 
struct helper<TAG> 
{ 
    static void print_tag(std::ostream& out) 
    { 
     out << std::string("Tag"); 
     out << TAG::get_id(); // Here I can't call: error: 'template<class> class TAG' used without template parameters 
    } 
}; 
template <template<typename> class TAG, template<typename> class... TAGS> 
struct helper<TAG, TAGS...> 
{ 
    static void print_tag(std::ostream& out) 
    { 
     out << std::string("Tag"); 
     out << TAG::get_id(); // Here I can't call: error: 'template<class> class TAG' used without template parameters 
     out << std::string(", "); 
     helper<TAGS...>::print_tag(out); 
    } 
}; 

//this class uses tags for some processing 
template <template<typename> class... TAG_LIST> 
class tagged 
{ 
public: 
    void test1(std::ostream& out) 
    { 
     out << std::string("This function works good"); 
    } 
    void test2(std::ostream& out) 
    { 
     helper<TAG_LIST...>::print_tag(out); 
    } 
}; 

// this class is re-defined for some types of T 
template<typename T, typename PARAM> 
class usage 
{ 
public: 
    void test1(std::ostream& out) 
    { 
     details.test1(out); 
    } 
    void test2(std::ostream& out) 
    { 
     details.test2(out); 
    } 

    T details; 
    PARAM params; 
}; 

//endpoint 
struct finish{}; 

//definition for future usage 
template<template<typename> class T1, template<typename> class T2, template<typename> class T3, typename PARAM> 
using multitag = usage<tagged<T1, T2, T3>, PARAM>; 

int main(int argc, const char* argv[]) 
{ 
    // this way I am construction my objects tree 
    multitag<tag1, tag2, tag3, tag1<tag2<tag3<finish>>>> tmp; 
    tmp.test1(std::cout); // ok 
    std::cout << std::endl; 
    tmp.test2(std::cout); //compile error. I want to get "Tag1, Tag2, Tag3" printed 
    std::cout << std::endl; 
} 
+1

'タグ:: GET_IDは()' は動作しません。 tag1/tag2/tag3の定義に従って、あなたがそれを置いた理由を問わず、PARAMと呼ばれるテンプレートパラメータを提供する必要があります。 'TAG :: get_id()'を変更し、メンバ関数 'get_id'をpublicにするだけでコンパイルできました。 – Arunmu

答えて

2
multitag<tag1, tag2, tag3, tag1<tag2<tag3<finish>>>> tmp; 

これはtmpのためのあなたの定義である、あなただけのテンプレートの種類である、tag1に渡しますエイリアス

template<typename PARAM> 
using tag1 = tag_<1UL, PARAM>; 

ただし、テンプレートパラメータPARAMは提供されていません。 だから、あなたはそれを使用したい場合、

out << TAG::get_id() 

あなたはそれをパラメータを与える必要があり、例えば

out << TAG<dummy>::get_id(); 

dummy何もすることができ、例えば、

class dummy{}; 

http://coliru.stacked-crooked.com/a/bb1d924dc3d5b774

+0

これは私が探していたものです。私の場合、PARAMの代わりにどのようなタイプ(空白の作業も含む)を使用するというアイデアは、この問題を解決します。私は関数内で正しいPARAM構造体にアクセスすることができず、パラメータとして渡すことはできません。このようにして、コードの生産性が低下しますが、それは私にとっては受け入れられます – Evgeniy

1

あなたが得ることができる最も近いものは、スペシャルを宣言することです各tagXためlization:TAGは完全な型ではないので

template <template <typename> class TAG> struct tag_id; 

template <> struct tag_id<tag1> : std::integral_constant<unsigned long, 1UL> {}; 
template <> struct tag_id<tag2> : std::integral_constant<unsigned long, 2UL> {}; 
template <> struct tag_id<tag3> : std::integral_constant<unsigned long, 3UL> {}; 
out << tag_id<TAG>{}; 

DEMO

+0

ありがとうございます。このコードは、よりよく設計されているように好まれます。しかし、私の場合、私はPARAM引数としていくつかの余分な構造体を使用する方が好きです。なぜなら、私は各タグの特殊化を宣言したくないからです – Evgeniy

関連する問題