简体   繁体   English

可变模板中递归模板函数的终止问题

[英]Termination issue on recursive template function in variadic template

I am trying to create a utility class that will call a specific function on all classes in a list. 我正在尝试创建一个实用程序类,该实用程序类将在列表中的所有类上调用特定函数。 The purpose behind this is to automate an element of reflection within a hierarchy of classes. 其背后的目的是使类的层次结构中的反射元素自动化。

I'm using Visual Studio 2015 to compile some C++ code and I'm getting a compile error when the recursive template function is unfolded because the compiler is having trouble distinguishing between the recursive function and the terminating function. 我正在使用Visual Studio 2015编译一些C ++代码,并且在递归模板函数展开时遇到编译错误,因为编译器在区分递归函数和终止函数时遇到麻烦。

I've extracted out the core of the class to a simple test case: 我已经将类的核心提取到一个简单的测试用例中:

#include <iostream>

template< typename ... BaseClasses >
class Meta
{
public:
    virtual ~Meta() {}

    template< typename T >
    void call(const T& val)
    {
        callOnAllClasses<T, BaseClasses...>(val);
    }

private:
    template< typename T, typename HeadClass >
    void callOnAllClasses(const T& val)
    {
        auto pObj = dynamic_cast<HeadClass*>(this);
        if ( pObj )
            pObj->HeadClass::doSomething(val);
    }

    template< typename T, typename HeadClass, typename ... TailClasses >
    void callOnAllClasses(const T& val)
    {
        auto pObj = dynamic_cast<HeadClass*>(this);
        if ( pObj )
            pObj->HeadClass::doSomething(val);
        callOnAllClasses<T, TailClasses...>(val);
    }
};

class A
{
public:
    void doSomething(int i)
    {
        std::cout << "A:" << i << std::endl;
    }
};

class B
{
public:
    void doSomething(int i)
    {
        std::cout << "B:" << i << std::endl;
    }
};

class C : public B, public A, public Meta<C,B,A>
{
    public:
    void doSomething(int i)
    {
        std::cout << "C:" << i << std::endl;
    }
};

int main()
{
    C c;
    c.call(5);
}

This results in the following error when compiled in Visual Studio 2015: 在Visual Studio 2015中编译时会导致以下错误:

error C2668: 'Meta<C,B,A>::callOnAllClasses': ambiguous call to overloaded function
could be 'void Meta<C,B,A>::callOnAllClasses<T,A,>(const T &)'
or       'void Meta<C,B,A>::callOnAllClasses<T,A>(const T &)'

I've never used variadic templates before so I'm at a bit of a loss as to why this might be going wrong. 我以前从未使用过可变参数模板,所以对于为什么会出错,我有点茫然。 Any help would be much appreciated! 任何帮助将非常感激!

You problem can be minimized as follows: 您的问题可以最小化,如下所示:

template< typename ... Bases >
struct Meta
{
    template< typename T >
    void call(const T& val)
    {
        callOnAllClasses<T, Bases...>(val);
    }

    template< typename T, typename HeadClass >
    void callOnAllClasses(const T& val)
    {

    }

    template< typename T, typename HeadClass, typename ... TailClasses >
    void callOnAllClasses(const T& val)
    {
        callOnAllClasses<T, TailClasses...>(val);
    }
};

struct C : Meta<int, int, int> { };

int main()
{
    C{}.call(5);
}

When TailClasses is empty, both these signatures are ambiguous to the compiler: TailClasses为空时,这两个签名对于编译器都是模棱两可的:

template< typename T, typename HeadClass >
void callOnAllClasses(const T& val);

template< typename T, typename HeadClass, typename ... TailClasses >
void callOnAllClasses(const T& val);

Adding an extra template argument to the recursive case helps the compiler disambiguate between the variadic and non-variadic overloads when TailClasses is empty. TailClasses为空时,在递归的情况下添加一个额外的模板参数有助于编译器消除可变重载和非可变重载之间的歧义。

template< typename T, typename HeadClass, typename T1, typename ... TailClasses >
void callOnAllClasses(const T& val)
{
    auto pObj = dynamic_cast<HeadClass*>(this);
    if ( pObj )
        pObj->HeadClass::doSomething(val);
    callOnAllClasses<T, T1, TailClasses...>(val);
}

live example on godbolt 实时演示

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

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