1

我定义了一个简单的模板类。在这个类中,我定义了一个用于图节点的结构(struct NodeData)。对于我在下面给出的第一个代码,即使我在方法测试中故意犯了错误,也没有编译错误(g[nId].anything = "something"即使 struct NodeData 没有名为任何变量的变量)。

为了理解问题出在哪里,在下面给出的第二个代码中,我将结构定义和 typedef 放在了 MyClass 之外。我已经把template<typename T1, typename T2>结构 NodeData 的定义放在了上面,因为这个结构需要存储 2 个抽象类型 T1 和 T2 的变量。我还typename从 typedefs 中删除了关键字,并且我在第一个 typedef 中放置NodeData<int, int>了而不是NodeData(即使我实际上不想这样做),否则它会在这一行出现一些错误,例如:expected a type, got 'NodeData'. 当我编译时,它给出了以下预期的错误(这实际上是完全正常的):,'struct NodeData<int, int>' has no member named 'anything'而对于第一个代码我没有得到这个错误!

这两个代码有什么区别?如何使第二个代码不必为第一个 typedef 指定 NodeData(因为 struct NodeData 的成员 var1 和 var2 不一定是 int 类型)?或者我怎样才能让第一个代码正常工作并检测 NodeData has no member named 的错误anything

第一个代码:

#include <iostream>
#include <boost/graph/adjacency_list.hpp>

using namespace std;
using namespace boost;

template<typename T1, typename T2>
class MyClass
{
    public:
        MyClass();
        virtual ~MyClass();
        void test(T1 p, T2 s);

    protected:
        struct NodeData
        {
            T1 var1;
            T2 var2;
            int var3;
        };

        struct EdgeData
        {
            int var;
        };

        typedef adjacency_list<setS, setS, undirectedS, NodeData, EdgeData> Graph;
        typedef typename Graph::vertex_descriptor NodeDataID;
        typedef typename Graph::edge_descriptor EdgeDataID;
        typedef typename graph_traits<Graph>::vertex_iterator VertexIterator;

        Graph g;
};

template<typename T1, typename T2>
void MyClass<T1, T2>::test(T1 arg1, T2 arg2)
{
    NodeDataID nId = add_vertex(g);
    g[nId].anything = "but anything is not in struct NodeData !";
    g[nId].var1 = arg1;
    g[nId].var2 = arg2;
    g[nId].var3 = 55;
}

template<typename T1, typename T2>
MyClass<T1, T2>::MyClass()
{
    // ...
}

template<typename T1, typename T2>
MyClass<T1, T2>::~MyClass()
{
    // ...
}

第二个代码:

#include <iostream>
#include <boost/graph/adjacency_list.hpp>

using namespace std;
using namespace boost;

template<typename T1, typename T2>
struct NodeData
{
    T1 var1;
    T2 var2;
    int var3;
};

struct EdgeData
{
    int var;
};

typedef adjacency_list<setS, setS, undirectedS, NodeData<int, int>, EdgeData> Graph;
typedef Graph::vertex_descriptor NodeDataID;
typedef Graph::edge_descriptor EdgeDataID;
typedef graph_traits<Graph>::vertex_iterator VertexIterator;

template<typename T1, typename T2>
class MyClass
{
    public:
        MyClass();
        virtual ~MyClass();
        void test(T1 p, T2 s);

    protected:
        Graph g;
};

template<typename T1, typename T2>
void MyClass<T1, T2>::test(T1 arg1, T2 arg2)
{
    NodeDataID nId = add_vertex(g);
    g[nId].anything = "but anything is not in struct NodeData !";
    g[nId].var1 = arg1;
    g[nId].var2 = arg2;
    g[nId].var3 = 55;
}

template<typename T1, typename T2>
MyClass<T1, T2>::MyClass()
{
    // ...
}

template<typename T1, typename T2>
MyClass<T1, T2>::~MyClass()
{
    // ...
}
4

1 回答 1

2

如果没有模板的实例化,则没有生成代码,因此不存在编译错误。这就是为什么通常有一些测试代码很重要的原因,这些代码可以对您的模板进行一些可能的实例化,并使用它们来确保您没有犯任何愚蠢的错误。

编辑:使用您的一些代码添加了一个示例,以防我不清楚我在说什么。

#include <iostream>

template<typename T1, typename T2>
class MyClass
{
public:
    void Test(T1 p, T2 s);

protected:
    struct NodeData
    {
        T1 var1;
        T2 var2;
        int var3;
    };

private:
    NodeData m_g;
};

template<typename T1, typename T2>
void MyClass<T1, T2>::Test(T1 arg1, T2 arg2)
{
    // error C2039: 'anything' is not a member of 'MyClass<T1,T2>::NodeData'
    m_g.anything = "but anything is not in struct NodeData !";
    m_g.var1 = arg1;
    m_g.var2 = arg2;
    m_g.var3 = 55;
}

int main() {
    // if you comment out the lines using it the template will never be compiled
    MyClass<int, double> test; // instantiation of template with T1 = int and T2 = double
    test.Test(42, 3.14); // calling Test function

    std::cin.get();
    return 0;
}
于 2012-01-24T20:49:31.007 回答