简体   繁体   English

可变参数模板递归类型传递

[英]Variadic template recursive types passing

I found almost satisfying solution for my problem here (2nd answer), but I cant use code written this way in another compilation unit, since putting code in header file causes linker to complain about multiple function definition and putting only declaration in header file causes linker undefined reference problem. 我在这里找到了几乎令人满意的解决方案(第二个答案),但是我不能在另一编译单元中使用这种方式编写的代码,因为将代码放入头文件会导致链接器抱怨多个函数定义,而仅将声明放在头文件会导致链接器未定义的参考问题。

Here is my code: 这是我的代码:

template <typename... types>
void foo();

template<>
void foo<>() {
    return;
}

template<typename type, typename... types>
void foohelper() {
    foo<types...>();
}

template <typename... types>
void foo() {
    foohelper<types...>();
}

int main() {
    foo<int, int>();
}

And here is what I want to achieve: 这是我想要实现的目标:

class A {
public:
    template<>
    void foo<>() {
        return;
    }

    template<typename parser, typename... parsers>
    void foohelper() {
        foo<parsers...>();
    }

    template <typename... parsers>
    void foo() {
        foohelper<parsers...>();
    }
};

int main() {
    A a;
    a.foo<int, int>();
}

But this causes following error during compilation: 但这在编译过程中导致以下错误:

explicit specialization 'void A::foo(void)' is not a specialization of a function template

Is there any simple solution for this? 有什么简单的解决方案吗?

no need for recursion. 无需递归。 This is simpler: 这比较简单:

#include <iostream>
#include <string>
#include <typeinfo>

class A {
public:

    template<typename parser>
    void foohelper() {
        std::cout << "handled a " << typeid(parser).name() << std::endl;
        // do work here
    }

    template <typename... parsers>
    void foo() {
        using expand = int[];
        (void) expand { 0, (foohelper<parsers>(), 0)... };
    }
};

int main() {
    A a;
    a.foo<int, int, double, std::string>();
}

sample output: 样本输出:

handled a i
handled a i
handled a d
handled a NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE

EDIT: 编辑:

In response to the non-conforming microsoft compiler requirement, here's another version that does not rely on an unsized array: 为了响应不符合要求的Microsoft编译器的要求,这是另一个不依赖未调整大小数组的版本:

#include <iostream>
#include <string>
#include <typeinfo>

class A {
public:

    template<typename parser>
    void foohelper() {
        std::cout << "handled a " << typeid(parser).name() << std::endl;
        // do work here
    }

    template <typename... parsers>
    void foo() {
        // c++ strictly does not allow 0-sized arrays.
        // so here we add a NOP just in case parsers is an empty type list
        using expand = int[1 + sizeof...(parsers)];
        (void) expand {
            (foohelper<void>(), 0),
            (foohelper<parsers>(), 0)...
        };
    }

};

// implement the NOP operation. Note specialisation is outside class definition.
template<> void
A::foohelper<void>() {}



int main() {
    A a;
    a.foo<int, int, double, std::string>();
    a.foo<>();
}

EDIT 2: 编辑2:

fuller example with prefix, postfix and inter-parser call-outs. 带有前缀,后缀和解析器间标注的完整示例。 Having written this much code, you'll probably start thinking, "Hey! I could implement a whole domain-specific language here!", and you'd be right. 编写了这么多代码之后,您可能会开始思考:“嘿!我可以在这里实现整个领域特定的语言!”,您将是对的。

However, much more complexity than this will probably earn you the eternal hatred of your colleagues, so I would avoid going down that route. 但是,复杂性远不止于此,这可能会使您对同事产生永恒的仇恨,因此,我将避免走这条路。

#include <iostream>
#include <string>
#include <typeinfo>

class A {
public:

    template<typename parser>
    void foohelper() {
        std::cout << "handled a " << typeid(parser).name();
        // do work here
    }

    void prepare()
    {
        std::cout << "starting parsers: ";
    }

    void separator()
    {
        std::cout << ", ";
    }

    void nothing()
    {

    }

    void done() {
        std::cout << " done!" << std::endl;
    }

    template <typename... parsers>
    void foo() {
        // c++ strictly does not allow 0-sized arrays.
        // so here we add a NOP just in case parsers is an empty type list
        bool between = false;
        using expand = int[2 + sizeof...(parsers)];
        (void) expand {
            (prepare(), 0),
            ((between ? separator() : nothing()), between = true, foohelper<parsers>(), 0)...,
            (done(), 0)
        };
    }

};


int main() {
    A a;
    a.foo<int, int, double, std::string>();
    a.foo<>();
}

sample output: 样本输出:

starting parsers: handled a i, handled a i, handled a d, handled a NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE done!
starting parsers:  done!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM