[vc 8,9][bug?] "Спецэффект" при неявном инстанцировании
От: rg45 СССР  
Дата: 25.12.09 12:16
Оценка: 31 (1)
Привет всем!

Столкнулся со странным поведением 8 и 9-ой студии при неявном инстанцировании шаблонных классов при использовании указателей на их статические члены во время компиляции. Как известно, параметрами шаблонов могут являться указатели на объекты с внешним связыванием. И вот, если определить шаблонную функцию, принимающую такой указатель, а потом параметризовать ее указателем на статическую переменную шаблонного класса, то возникает ошибка линковки "unresolved external symbol", говорящая о том, что статический член шаблонного класса не был инстанцирован. Если же шаблонную функцию заменить шаблонным классом, то ошибка уходит. На VC-7.1 данная проблема не проявляется. Вот минимальный код, воспроизводящий проблему:
#include <iostream>

template<const int* value>
struct Test {
  static void test() { std::cout << *value << std::endl; }
};

template<const int* value>
void test() { std::cout << *value << std::endl; }

template<typename T> 
struct Host { 
  static T instance; 
};
template<typename T> T Host<T>::instance;

int main()
{
  test<&Host<int>::instance>(); //error LNK2001: unresolved external symbol "public: static int Host<int>::instance"
  //Test<&Host<int>::instance>::test();
}

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

Посмотрел, что говорит стандарт по вопросам неявного инстанцирования, ничего близкого к теме не нашел. Может кто-нибудь дать объяснение этому "спецэффекту"?
--
Справедливость выше закона. А человечность выше справедливости.
Re: [vc 8,9][bug?] "Спецэффект" при неявном инстанцировании
От: Николай Ивченков  
Дата: 25.12.09 15:20
Оценка: 7 (1)
VC++ не прав, т.к. определение data member-a у тебя дано. Причину его инстанцирования следует искать в 14.7.1/1, 3.2/2 и 3.2/3.
Re: GCC 4.4 компилирует (-)
От: Roman Odaisky Украина  
Дата: 26.12.09 11:52
Оценка:
До последнего не верил в пирамиду Лебедева.
Re[2]: GCC 4.4 компилирует (-)
От: rg45 СССР  
Дата: 26.12.09 15:09
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

А линкует? Ведь VC-8,9 тоже компилируют, ошибка при линковке.
--
Справедливость выше закона. А человечность выше справедливости.
Re[3]: И линкует (-)
От: Roman Odaisky Украина  
Дата: 26.12.09 17:20
Оценка: 7 (1)
R>А линкует? Ведь VC-8,9 тоже компилируют, ошибка при линковке.

Линкует. Я думал, это подразумевается.
До последнего не верил в пирамиду Лебедева.
Re: [vc 8,9][bug?] "Спецэффект" при неявном инстанцировании
От: rg45 СССР  
Дата: 28.12.09 09:59
Оценка:
Здравствуйте, rg45, Вы писали:

R>Привет всем!


R>Столкнулся со странным поведением 8 и 9-ой студии при неявном инстанцировании шаблонных классов при использовании указателей на их статические члены во время компиляции. Как известно, параметрами шаблонов могут являться указатели на объекты с внешним связыванием. И вот, если определить шаблонную функцию, принимающую такой указатель, а потом параметризовать ее указателем на статическую переменную шаблонного класса, то возникает ошибка линковки "unresolved external symbol", говорящая о том, что статический член шаблонного класса не был инстанцирован. Если же шаблонную функцию заменить шаблонным классом, то ошибка уходит. На VC-7.1 данная проблема не проявляется. Вот минимальный код, воспроизводящий проблему:

R>
R>#include <iostream>

R>template<const int* value>
R>struct Test {
R>  static void test() { std::cout << *value << std::endl; }
R>};

R>template<const int* value>
R>void test() { std::cout << *value << std::endl; }

R>template<typename T> 
R>struct Host { 
R>  static T instance; 
R>};
R>template<typename T> T Host<T>::instance;

R>int main()
R>{
R>  test<&Host<int>::instance>(); //error LNK2001: unresolved external symbol "public: static int Host<int>::instance"
R>  //Test<&Host<int>::instance>::test();
R>}
R>

R>Если раскомментировать последнюю строку в функции main, то инстанцирование выполняется и ошибка исчезает.

Что интересно, ошибка не уходит даже в том случае, если шаблонную функцию test<>() реализовать посредством Test<>::test():
template<const int* value> test() { Test<value>::test(); }

И это не смотря на то, что использование Test<>::test() вместо ::test<>() решает проблему.

В качестве меры, нейтрализующей ошибку, можно использовать фиктивный формальный параметр со значением по умолчанию:
template<const int* value>
void test(const int* = value) 
{ 
  std::cout << *value << std::endl; 
}
--
Справедливость выше закона. А человечность выше справедливости.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.