Сбой специализации шаблона при связывании - PullRequest
8 голосов
/ 15 июля 2011

У меня проблема со специализацией шаблонов, которую я хотел бы понять. Я работаю с Visual C ++ 10.0 (2010). У меня есть такой класс:

class VariableManager
{
public:

    template<typename VarT>
        VarT get(std::string const& name) const
        {
                    // Some code...
        }

   // This method supposed to be fully evaluated, linkable method.   
    template<>
        std::string get<std::string>(std::string const& name) const;

private:
    std::map<std::string, boost::any> mVariables;
};

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

    template<>
    std::string VariableManager::get<std::string>(std::string const& name) const
            {
                 // Doing something...
            }

Если я помещаю этот метод в заголовочный файл как встроенный, сборка идет очень хорошо. Я понимаю, что шаблон работает так:

        template<typename VarT>
            VarT get(std::string const& name) const;

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

Ответы [ 3 ]

11 голосов
/ 15 июля 2011

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

Если вы правильно включили соответствующий файл .cpp, который содержит определение явной специализации, в ваш проект, то VC ++ не должен вызывать ошибку компоновщика. Что касается соответствия стандартам, позвольте мне отметить, что вы должны объявить свою специализацию вне включающего класса. Стандарт запрещает объявлять явные специализации внутри включающего класса (и другие компиляторы отклонят ваш код). Поэтому измените заголовочный файл, чтобы объявить специализацию следующим образом:

class VariableManager
{
public:

    template<typename VarT>
        VarT get(std::string const& name) const
        {
                    // Some code...
        }

private:
    std::map<std::string, boost::any> mVariables;
};

// This method supposed to be fully evaluated, linkable method.   
template<>
std::string VariableManager::get<std::string>(std::string const& name) const;

Позвольте мне также отметить, что вы не можете звонить get<std::string> внутри своего класса. Это связано с тем, что любой такой вызов еще не видел бы явного объявления специализации и, следовательно, пытался создать экземпляр функции из определения шаблона. Стандарт делает такой код неверным, без необходимости диагностики.

0 голосов
/ 15 июля 2011

Метод, начинающийся с template<>, по-прежнему считается template метод специализации . Таким образом, вы должны положить в заголовочный файл.

Если вы хотите поместить его в файл реализации, вам нужно перегрузить it.

class VariableManager
{
//...
  VarT get(std::string const& name) const
  {}

  std::string get(std::string const& name) const; //overloading not specialization
};
0 голосов
/ 15 июля 2011

Специализация шаблона не заставляет компилятор создавать его экземпляры (хотя я думаю, что GCC делает это); вам все еще нужно явно указать компилятору на самом деле создать экземпляр шаблона. Вы можете сделать это с явным созданием шаблона. В основном, просто добавьте это в исходный файл:

template std::string VariableManager::get(const std::string& name) const;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...