Создание экземпляров шаблонных функций C++

Я столкнулся с несколькими проблемами с ошибками «неопределенная ссылка на». Возможно, я не смогу опубликовать код, но объявления и способ вызова функций следующие:

Декларации:

template <typename T>
int pitch_detect(deque<T>& x, int offset, int len);

template <typename T>
int is_voiced(
  deque<T>& x, int offset, int len,
  double avg_energy, int pre_voice,
  short& s_flag,
  long nsamples
);

Я вызываю вышеуказанные функции следующим образом:

x = is_voiced(superFrame_, cur_offset_, f_len_,
    avgEnergy_, frame_voicing_[1], silence_flag_, nsamples_);

y = pitch_detect(superFrame_, cur_offset_, f_len_);

Приведенные выше операторы (где я вызываю функции) помечаются как ошибки. Это сообщения:

неопределенная ссылка на `int is_voiced(std::deque >&, int, int, double, int, short&, long)

неопределенная ссылка на `int pitch_detect(std::deque >&, int, int)'

Приветствуется любая помощь в расшифровке вышеуказанных ошибок. Спасибо, Шрирам

Изменить: вышеуказанные функции определены в отдельном заголовке и соответствующем файле C++. У меня не возникает проблем, когда я пытаюсь их скомпилировать и создать объектный файл. Эти ошибки видны на этапе компоновщика.


person Sriram    schedule 21.06.2010    source источник


Ответы (3)


Вы предоставили определения для этих шаблонов? Вы явно создаете экземпляры шаблонов сами или позволяете компилятору создавать их экземпляры?

Если вы предоставите объявление шаблона, но компилятор не увидит определение в той же единице трансляции, он предположит, что экземпляр шаблона будет создан в другой единице трансляции, и просто сгенерирует вызов, но не скомпилирует (не видя определения, которое оно не может этого сделать) конкретного экземпляра. Позже, во время компоновки, компоновщик увидит вызов, но не увидит экземпляр и завершится ошибкой undefined reference.

Самое простое решение — просто объединить объявление и определение шаблона:

template <typename T>
int is_voiced( deque<T>& x, int offset, int len, double avg_energy, int pre_voice, short& s_flag, long nsamples ) 
{
  // code here
}

Затем, когда вы используете is_voiced(...), компилятор неявно создаст экземпляр шаблона для вас (он увидит код и скомпилирует его).

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

// header
template <typename T>
int is_voiced( deque<T>& x, int offset, int len, double avg_energy, int pre_voice, short& s_flag, long nsamples ); 

// cpp
template <typename T>
int is_voiced( deque<T>& x, int offset, int len, double avg_energy, int pre_voice, short& s_flag, long nsamples ) {
   // code goes here
}
// explicit instantiation for int
template int is_voiced( deque<int>& x, int offset, int len, double avg_energy, int pre_voice, short& s_flag, long nsamples );

Затем скомпилируйте этот файл реализации и свяжите его с остальной частью проекта.

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

person David Rodríguez - dribeas    schedule 21.06.2010
comment
Ах! Да. В этом была проблема. Я не создавал шаблоны явно. Я новичок в шаблонах, и мне нужно многому научиться. Задача решена! Спасибо, Дэвид! - person Sriram; 21.06.2010
comment
Вам действительно нужно использовать явное создание экземпляров? В большинстве случаев лучше просто предоставить определение шаблона в заголовке и заставить компилятор неявно создавать его экземпляр при использовании. - person David Rodríguez - dribeas; 21.06.2010

Поместите определения функций в заголовочный файл, а не в отдельный файл CPP; и в заголовочном файле добавьте к определениям функций префикс ключевого слова inline, чтобы компоновщик не жаловался на повторяющиеся определения.

person ChrisW    schedule 21.06.2010

Я не пробовал g++, но пробовали ли вы явно называть тип?

x = is_voiced<PutTypeNameHere>(superFrame_, etc);

Определения и вызовы выполняются из одной и той же dll/exe? Если нет, вам может потребоваться явно создать экземпляр функций шаблона с типами, с которыми вы их вызываете.

person Scott Langham    schedule 21.06.2010
comment
Я не создавал явным образом функции шаблона. В этом была проблема. Спасибо Скотт! - person Sriram; 21.06.2010