使用部分类型知识访问模板的参数

时间:2016-05-30 07:15:53

标签: c++ c++11 variadic-templates

我有一些深度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;
}

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

最接近的是为每个tagX声明一个专门化:

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>{};

Set Up the NativeScript CLI on OS X