繁体   English   中英

模板和前向声明

[英]template and forward declaration

class VisitorBase;

template<typename R = void>
class BaseVisitable
{
public:
    typedef R RetType;
    virtual ~BaseVisitable() {}

    // Ok,only need forward-declaration of VisitorBase
    virtual R Accept(VisitorBase&) = 0; 
protected:
    template<typename T>
    static RetType AcceptImp(T& visited, VisitorBase& guest) // same as above
    {
        // there is neither forward-declaration nor definition of Visitor type,
        // how can it pass compilation?
        if (Visitor<T>* p = dynamic_cast<Visitor<T>*>(&guest)) 
        {
            return p->Visit(visited);
        }

        // Visitor<int> v; error
    }
};

这段代码摘自LOKI,上面我在注释中写了一些疑惑。

Visitor<T>前向声明是不够的,因为p->Visit(visited)调用了Visitor<T>的方法,这意味着必须通过include语句来声明Visitor<T>的声明。或同一文件中的Visitor<T>的定义。 否则,编译器没有任何线索, Visitor<T>具有成员Visit()

我假设您的摘录来自文件Visitor.h 如果包括前向声明template<class T> class Visitor;则摘录确实会编译template<class T> class Visitor; 在该文件中。

Visitor模板的前向声明足以在Visitor<T>上调用一个函数,因为它是一个依赖类型, AcceptImp模板的实例化将最终实例化具有给定类型的Visitor<T>模板。 届时,必须已定义Visitor<T> (并且该定义还必须具有被调用的函数)。 否则,将出现编译时错误。 如果完全不实例化AcceptImp模板,则不会有任何错误。

Visitor<int>不是从属类型,因此必须在定义AcceptImp而不是insantiated定义它。 由于未定义Visitor ,因此无法实例化Visitor<int>

这是一个简化的演示:

// forward declaration
template<class S>
struct Foo;

template<class T> 
void test(Foo<T>* f = nullptr) { // declaring a pointer is just fine
    if(f != nullptr)
        f->bar(); // calling a function is fine unless Foo<T> is incomplete or doesn't define bar
    // Foo<int> i; // oops, incomplete type, cannot do
    Foo<T> t; // Foo<T> must be complete when test<T> is instantiated, otherwise fails
}

// here's an example of what you can do
// let's define a specialization
template<>
struct Foo<int> {
    void bar(){}; // if we didn't define this, then we couldn't instantiate test<int>
};

// now you can instantiate Foo<int> and call test
int main() {
    Foo<int> i; // Foo<int> is a complete type now :)
    test(&i);
    // test<float>(); // oops, Foo<float> is incomplete
    //         test can't call Foo<float>::bar
    //         or instantiate an object of type Foo<float>
    //         Defining a pointer to Foo<T> in test would still be fine
}

暂无
暂无

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

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