2013-06-04 5 views
7

Я борюсь за доступ к статической функции-члену, определенной внутри шаблона класса. В файле заголовка TemplateTest.h Я определил шаблон основной класс как:static member function внутри класса шаблон специализация

#include<iostream> 

template<class T, class U> 
struct TemplateTest 
{ 
public: 
    void static invoke(); 
    /*{ 

     std::cout << "Should not be called" << std::endl; 

    }*/ 
}; 

Затем Source File TemplateTester.cpp я ставлю специализацию:

#include "TemplateTest.h" 

template<> 
struct TemplateTest<int, bool> 
{ 
    static void invoke() 
    { 
     std::cout << "invoke<int, bool>" << std::endl; 
    } 
}; 

template struct TemplateTest<int, bool>; //instantiate to resolve linker issue 

я явно инстанцированный класс с таким компоновщика решает правильно.

В driver.cpp драйвера:

include "TemplateTest.h" 

int main() 
{ 
    TemplateTest<int, bool>::invoke(); 
    return 0; 
} 

Когда я скомпилировать TemplateTest.cpp с г ++ он генерирует объектный файл правильно, но когда я пытаюсь связать его с классом драйвера он дает свою ошибку компоновщика " undefined ссылка на «TemplateTest :: invoke()»

Я прошел через другие связанные публикации, такие как this one, но я не пытаюсь получить доступ к шаблону функции.

Любой ключ приветствуется.

+4

Переместить реализацию в файл заголовка. реализация шаблона должна быть видимой для всех TU, использующих их. –

ответ

5

Вы правы, что объектный файл создается из TemplateTester.cpp будет содержать символ для специализации вы предоставили. Это связано с тем, что любая явная специализация заставляет шаблон создавать экземпляр, и это вдвойне, потому что вы даже добавили явное инстанцирование (что фактически не нужно).

Однако в то время, когда driver.cpp скомпилирован, компилятор не знает об этой специализации, так как вы включаете только TemplateTester.h, и специализация здесь не указана. Поэтому компилятор создает шаблон, конечно же, не используя специализированное определение, поэтому вы получаете свою проблему.

Стандарт говорит (Курсив мной):

(§ 14.7.3/6) Если шаблон, шаблон-член или член шаблона класса явно специализирован, то эта специализация должна быть объявлена ​​до первого использования этой специализации, которая вызовет неявное создание экземпляра, в каждой единицы перевода в что такое использование происходит; не требуется диагностика. Если программа не предоставляет определения для явной специализации, и либо специализация используется таким образом, чтобы вызвать неявное создание экземпляра, либо член является виртуальной функцией-членом, программа плохо сформирована, а диагностика не требуется. Имплицитная инстанция никогда не создается для явной специализации, которая объявлена, но не определена. [...]

Так что вам нужно сделать так, декларация и определение специализации, известной компилятору, когда он работает на driver.cpp. Лучший способ сделать это - добавить всю специализацию к TemplateTester.h.

Обратите также внимание на то, что явное инстанцирование на самом деле не требуется.

+1

Спасибо за объяснение @jogojapan. На самом деле это прототип статической библиотеки шаблонов, над которой я работаю. Теперь я вижу, почему он терпит неудачу. Думаю, я могу переместить определения, чтобы компилятор был счастлив. – jazaman

3

Есть несколько проблем:

  • вам не нужно явно создать экземпляр полностью СПЕЦИАЛИЗИРОВАННЫЙ шаблон
  • если вы хотите поставить статический метод в заголовке, а затем использовать inline. В противном случае вы получите несколько экземпляров и проблемы с компоновщиками
  • шаблоны, которые вы помещаете в заголовок, и определите методы в исходных файлах
  • , если вы не хотите, чтобы что-то вызывалось в шаблоне, вам не нужно определять Это. Вы получите ошибки компилятора, а это значит, что раньше были ошибки.

// TemplateTest.h 
#include<iostream> 

template<class T, class U> 
struct TemplateTest; 
template<> 
struct TemplateTest<int, bool> 
{ 
    inline static void invoke() 
    { 
     std::cout << "invoke<int, bool>" << std::endl; 
    } 
}; 

// main.cpp 
include "TemplateTest.h" 

int main() 
{ 
    TemplateTest<int, bool>::invoke(); 
} 

Другой способ изменить заголовок, и добавить исходный файл.

// TemplateTest.h 
#include<iostream> 

template<class T, class U> 
struct TemplateTest; 

template<> 
struct TemplateTest<int, bool> 
{ 
    static void invoke(); 
}; 

// TemplateTest.cpp 
#include "TemplateTest.h" 
void TemplateTest<int, bool>::invoke() 
{ 
    std::cout << "invoke<int, bool>" << std::endl; 
} 
+0

Спасибо @ BЈовић Я на самом деле пытался придумать прототип здесь. Может быть, я должен их прямо упомянуть. Шаблоны классов фактически являются частью статической библиотеки, и поэтому я думаю, что мне все равно понадобится создание экземпляра. Но вы правы, я не должен определять функцию внутри класса. Это нужно делать на улице. Я попробую это и посмотрю, разрешит ли он мою проблему. – jazaman

+0

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

+0

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

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