我试图使用从我的项目的子类的类型定义,我孤立我的问题在下面的例子。

有谁知道我要去哪里错了?

template<typename Subclass>
class A {
    public:
        //Why doesn't it like this?
        void action(typename Subclass::mytype var) {
            (static_cast<Subclass*>(this))->do_action(var);
        }
};

class B : public A<B> {
    public:
        typedef int mytype;

        B() {}

        void do_action(mytype var) {
            // Do stuff
        }
};

int main(int argc, char** argv) {
    B myInstance;
    return 0;
}

这是输出我得到:

sean@SEAN-PC:~/Documents/LucadeStudios/experiments$ g++ -o test test.cpp
test.cpp: In instantiation of ‘A<B>’:
test.cpp:10:   instantiated from here
test.cpp:5: error: invalid use of incomplete type ‘class B’
test.cpp:10: error: forward declaration of ‘class B’
有帮助吗?

解决方案

原因在于,实例化一个类模板时,其所有的它的成员函数的声明(不是定义)被实例化了。需要专业化的完整定义时类模板正是实例化。这是这样,当它被用作例如一个基类,如你的情况。

那么,什么情况是,A<B>

实例
class B : public A<B>

此时B不是一个完整的类型,但(它是类定义的闭括号之后)。然而,A<B>::action的声明要求B是完整的,因为它是在它的范围爬行:

Subclass::mytype

您需要做的是延迟实例化的一些点时B完成什么。这样做的一种方法是修改action的声明,使之成为成员模板。

template<typename T>
void action(T var) {
    (static_cast<Subclass*>(this))->do_action(var);
}

它仍然是类型安全的,因为如果var是不正确的类型,传递vardo_action将失败。

其他提示

您可以通过使用一个traits类解决这个问题:点击 它需要你建立一个specialsed traits类为每个使用实际工作类。

template<typename SubClass>
class SubClass_traits
{};

template<typename Subclass>
class A {
    public:
        void action(typename SubClass_traits<Subclass>::mytype var)
        {
                (static_cast<Subclass*>(this))->do_action(var);
        }
};


// Definitions for B
class B;   // Forward declare

template<> // Define traits for B. So other classes can use it.
class SubClass_traits<B>
{
    public:
        typedef int mytype;
};

// Define B
class B : public A<B>
{
    // Define mytype in terms of the traits type.
    typedef SubClass_traits<B>::mytype  mytype;
    public:

        B() {}

        void do_action(mytype var) {
                // Do stuff
        }
};

int main(int argc, char** argv)
{
    B myInstance;
    return 0;
} 

您获得从B A<B>,所以编译器,一旦它看到类B定义的第一件事就是尝试实例A<B>。要做到这一点就需要知道B::mytypeaction的参数。但是,因为编译器只是在搞清楚B的实际定义的过程,它并不知道这种类型还,你会得到一个错误。

解决此的一种方式是将声明参数类型作为另一模板参数,而不是内部的派生类:

template<typename Subclass, typename Param>
class A {
    public:
        void action(Param var) {
                (static_cast<Subclass*>(this))->do_action(var);
        }
};

class B : public A<B, int> { ... };

不正是你问,但你可以采取行动的模板成员函数:

template<typename Subclass>
class A {
    public:
        //Why doesn't it like this?
        template<class V> void action(V var) {
                (static_cast<Subclass*>(this))->do_action();
        }
};

class B : public A<B> {
    public:
        typedef int mytype;

        B() {}

        void do_action(mytype var) {
                // Do stuff
        }
};

int main(int argc, char** argv) {
    B myInstance;
    return 0;
}

您需要使用一个指针或作为适当的类型此时是不知道的参考编译器不能创建实例。

相反尝试:

void action(const typename Subclass::mytype &var) {
            (static_cast<Subclass*>(this))->do_action();
    }
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top