2012-01-24 2 views
1

У меня есть определенный класс шаблонов. В этом классе я определяю структуру (struct NodeData), которая используется для узлов графа. Для первого кода, который я даю ниже, нет ошибки компиляции, даже если я специально делаю ошибку в тесте метода (я делаю g[nId].anything = "something", даже если у структуры NodeData нет переменной, называемой чем-либо).структура, определенная вне или внутри шаблона класса

Чтобы понять, где проблема, во втором коде, который я даю ниже, я поместил определения своих структур и typedefs вне MyClass. Я положил template<typename T1, typename T2> поверх определения struct NodeData, потому что эта структура должна хранить 2 переменных абстрактного типа T1 и T2. Я также удалил ключевое слово typename из typedefs, и я поставил NodeData<int, int> вместо NodeData в первом typedef (даже если я не хочу этого делать на самом деле), иначе он даст некоторые ошибки в этой строке, например: expected a type, got 'NodeData'. Когда я компилирую, он дает следующую ожидаемую ошибку (что на самом деле абсолютно нормально): 'struct NodeData<int, int>' has no member named 'anything', а для первого кода я не получил эту ошибку!

В чем разница между этими двумя кодами? Как я могу сделать для второго кода не обязано указывать NodeData для первого typedef (поскольку члены var1 и var2 структуры NodeData не обязательно имеют тип int)? Или как я могу сделать, чтобы первый код работал правильно и обнаружил ошибку, в которой NodeData не имеет имени с именем 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() 
{ 
    // ... 
} 
+1

ли вы на самом деле вызвать функцию пустоте MyClass :: тест (T1 arg1, T2 arg2) в первом случае? Если это не так, он не создается и, следовательно, в вашем коде нет ошибки. – P3trus

+0

Ну, я еще не создал его, я все еще пишу код для него. Итак, наконец, первый код был абсолютно правильным? – shn

+0

Нет, это не так, но компилятор не видит ошибки, потому что не использует ее. – P3trus

ответ

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; 
} 
+0

Ну, есть ли хороший и правильный способ продолжить такие тесты, чтобы обнаружить глупые ошибки, когда код класса еще не закончен? – shn

+0

@ user995434 В случае, например, разработки, основанной на тестах, вы даже сначала пишете свой тест. Тест определяет, что должен делать ваш код. И затем вы пишете код до прохождения теста. – P3trus

+0

@ P3trus если я лоток, чтобы создать экземпляр, как показано ниже (только для проверки), я получаю ошибку компиляции: MyClass tst(); tst.test (3, 4); // или даже с tst.test (3, 4); Ошибка: запрос участника 'test' в 'tst', который не относится к классу 'MyClass ()' – shn

Смежные вопросы