2009-12-12 3 views
7

Мой полный код слишком длинный, но вот фрагмент, который будет отражать суть моей проблемы:Специализация шаблона после создания экземпляра?

class BPCFGParser { 
    public: 

    ... 
    ... 

    class Edge { 
    ... 
    ... 
    }; 


    class ActiveEquivClass { 
    ... 
    ... 
    }; 

    class PassiveEquivClass { 
    ... 
    ... 
    }; 

    struct EqActiveEquivClass { 
    ... 
    ... 
    }; 

    struct EqPassiveEquivClass { 
    ... 
    ... 
    }; 



    unordered_map<ActiveEquivClass, Edge *, hash<ActiveEquivClass>, EqActiveEquivClass> discovered_active_edges; 
    unordered_map<PassiveEquivClass, Edge *, hash<PassiveEquivClass>, EqPassiveEquivClass> discovered_passive_edges; 

}; 

namespace std { 


template <> 
class hash<BPCFGParser::ActiveEquivClass> 
{ 

    public: 
     size_t operator()(const BPCFGParser::ActiveEquivClass & aec) const { 

     } 
}; 

template <> 
class hash<BPCFGParser::PassiveEquivClass> 
{ 

    public: 
     size_t operator()(const BPCFGParser::PassiveEquivClass & pec) const { 

     } 
}; 

} 

Когда я скомпилировать этот код, я получаю следующие ошибки:

In file included from BPCFGParser.cpp:3, 
       from experiments.cpp:2: 
BPCFGParser.h:408: error: specialization of ‘std::hash<BPCFGParser::ActiveEquivClass>’  after instantiation 
BPCFGParser.h:408: error: redefinition of ‘class     std::hash<BPCFGParser::ActiveEquivClass>’ 
/usr/include/c++/4.3/tr1_impl/functional_hash.h:44: error: previous definition of  ‘class std::hash<BPCFGParser::ActiveEquivClass>’ 
BPCFGParser.h:445: error: specialization of  ‘std::hash<BPCFGParser::PassiveEquivClass>’ after instantiation 
BPCFGParser.h:445: error: redefinition of ‘class std::hash<BPCFGParser::PassiveEquivClass>’ 
/usr/include/c++/4.3/tr1_impl/functional_hash.h:44: error: previous definition of  ‘class std::hash<BPCFGParser::PassiveEquivClass>’ 

сейчас Мне нужно специализировать std :: hash для этих классов (поскольку стандартное определение std :: hash не включает определенные пользователем типы). Когда я перемещаю эти шаблонные специализации перед определением класса BPCFGParser, я получаю множество ошибок для различных вещей, которые я пытался, а где-то (http://www.parashift.com/c++-faq-lite/misc-technical-issues.html) Я читал это:

Всякий раз, когда вы используете класс в качестве параметра шаблона, декларация этот класс должен быть полным, а не просто объявленным вперед.

Так что я застрял. Я не могу специализировать шаблоны после определения BPCFGParser, я не могу специализировать их до определения BPCFGParser, как я могу заставить это работать?


Вы должны переместить специализацию во внутренний класс внутри BPCFGParser. Это соответствует обоим требованиям.

Большое спасибо за ответ :)

hash класс определен в пространстве имен std. Это не позволяет мне специализировать шаблоны для hash в области без пространства имен. Даже следующие:

template <> 
    class std::hash<ActiveEquivClass> { 
... 

не работал. Когда я заключаю специализаций с namespace std {}, однако, это дает странную ошибку:

In file included from BPCFGParser.cpp:3, 
       from experiments.cpp:2: 
BPCFGParser.h:225: error: expected unqualified-id before ‘namespace’ 
experiments.cpp:7: error: expected `}' at end of input 
BPCFGParser.h:222: error: expected unqualified-id at end of input 

В ответе приведены в velocityreviews, кто-то утверждает, что пространство имен не может быть определена в пределах классов. Поэтому я все еще застрял.

ответ

5

Вам нужно переместить специализацию во внутренний класс внутри BPCFGParser. Это соответствует обоим требованиям

  1. Специализация после полного определения ActiveEquivClass
  2. Перед использованием специализации

Пример:

class BPCFGParser { 

    class ActiveEquivClass { 
    ... 
    }; 

    template <> 
    class hash<ActiveEquivClass> { 
    public: 
     size_t operator()(const BPCFGParser::ActiveEquivClass & aec) const { 
     } 
    }; 
    ... 
    unordered_map<ActiveEquivClass, Edge *, hash<ActiveEquivClass>, EqActiveEquivClass> discovered_active_edges; 

}; 
+0

Большое спасибо за ответ, но он не работает. Ниже приведено объяснение. –

1

Попробуйте переместить хэш <> шаблон код специализации перед объявлением класса BPCFGParser. Ошибка означает, что хэш расширяется на основе std :: hash, определенного в /usr/include/c++/4.3/tr1_impl/functional_hash.h; Поэтому ваша специализация не используется до создания. В идеале ваш код специализации должен быть доступен для компилятора до того, как шаблон будет расширен.

0

Всякий раз, когда вы используете класс в качестве параметра шаблона, объявление того класса должно быть полным, а не просто объявленным вперед.

На самом деле это не так. Ограничения того, когда параметры шаблона должны быть полными типами, обычно зависят от содержимого шаблона; но не является незаконным создание шаблона с неполным типом, если шаблон не содержит код, который является незаконным с неполным типом.

Единственный способ приблизиться к вашей проблеме заключается в определение специализации перед классом, но для определения фактической функции-члена operator()после класса. То есть

template <> 
class std::hash<BPCFGParser::ActiveEquivClass> 
{ 
public: 
    size_t operator()(const BPCFGParser::ActiveEquivClass & aec) const; 
}; 

// definition of BPCFGParser 

template<> std::size_t std::hash<BPCFGParser::ActiveEquivClass>::operator()(const BPCFGParser::ActiveEquivClass & aec) const { 
} 

Это также означает, что нет вложенных классов, поскольку вы не можете переслать объявление вложенного класса.

0

Я точно такая же проблема, и, наконец, придумали обходной определенный пользователем решения хэш-функтора, смотрите ниже:

class Outer 
{ 
    // TC++PL, 4e, 19.4.1 : A friend must be previously declared in an enclosing scope or 
    // defined in the non-class scope immediately enclosing the class that is declaring it to be a friend. 
    struct Hash_inner; 

    class Inner 
    { 
     int i; 
     friend struct Hash_inner; 
    }; 

    struct Hash_inner 
    { 
     size_t operator()(const Inner& in) const 
     { return std::hash<int>()(in.i); } 
    }; 

    std::unordered_map<Inner, int, Hash_inner> um; 
}; 

И я стил интересно, есть ли специализация подход станд :: хэш , Может ли кто-нибудь понять это?

0

Я знаю, что этот вопрос довольно старый, но я только что столкнулся с одной проблемой, и я подумал, что расскажу о своих выводах.

Сообщение об ошибке:

In file included from BPCFGParser.cpp:3, 
      from experiments.cpp:2: 
BPCFGParser.h:408: error: specialization of ‘std::hash<BPCFGParser::ActiveEquivClass>’  after instantiation 
BPCFGParser.h:408: error: redefinition of ‘class     std::hash<BPCFGParser::ActiveEquivClass>’ 
/usr/include/c++/4.3/tr1_impl/functional_hash.h:44: error: previous definition of  ‘class std::hash<BPCFGParser::ActiveEquivClass>’ 
BPCFGParser.h:445: error: specialization of  ‘std::hash<BPCFGParser::PassiveEquivClass>’ after instantiation 
BPCFGParser.h:445: error: redefinition of ‘class std::hash<BPCFGParser::PassiveEquivClass>’ 
/usr/include/c++/4.3/tr1_impl/functional_hash.h:44: error: previous definition of  ‘class std::hash<BPCFGParser::PassiveEquivClass>’ 

не жалуясь ваших классов вообще, это говорит, что вы не можете специализироваться зЬй :: хэш, потому что либо общий шаблон для станд :: хэш или один из существующие специализации уже использовались - то есть кто-то использовал его между тем, что он был определен, и точкой, в которой вы пытаетесь ее специализировать.

Существует некоторый текст, описывающий это в разделе «подробно» из this document:

Специализация должны быть объявлены до первого использования, что приведет к неявной конкретизации

В моем случае, проблема была не в моем коде специализации, проблема была в его положении. Когда std :: hash используется вообще, вы не можете его специализировать.

Я обнаружил, что если я переместил свой код специализации сразу после включения <unordered_map>, он работал нормально.

Предположение Puppy, чтобы отделить декларацию специализации от реализации позволяет перемещать заявления очень близко к включению <unordered_map>, реализация может прийти позже, где это удобно (после BPCFGParser полностью определена в вашем дело).