Знатокам стандарта
От: Непомнящий Евгений  
Дата: 01.07.08 05:04
Оценка:
Подскажите, должно ли это компилироваться:
static void funcA(void *p) {}

template<class T>
void funcT(T &t)
{
  funcA(&t);
}

void test()
{
  int t;
  funcT(t);
}


Визуал С 2005 и GCC 3.4.5 компилят. IAR — нет:
Error[Pe304]: no instance of function "funcA" matches the argument list
argument types are: (int *)
detected during instantiation of "void funcT(T &) [with T=int]"

Его разрабы говорят, что это правильно.

Если можно — ткните в стандарт...
... << RSDN@Home 1.2.0 alpha 3 rev. 880>>
Re: Знатокам стандарта
От: codelord  
Дата: 01.07.08 05:56
Оценка:
Здравствуйте, Непомнящий Евгений, Вы писали:
g++ (GCC) 4.1.1 20070105 (Red Hat 4.1.1-51)
скомпилил и даже не заикнулся
Re: Знатокам стандарта
От: shank  
Дата: 01.07.08 06:01
Оценка: 12 (2)
Здравствуйте, Непомнящий Евгений, Вы писали:

НЕ>Если можно — ткните в стандарт...


Пример можно немного упростить:
static void funcA(int p) {}

template<class T>
void funcT(T t)
{
  funcA(t);
}

void test()
{
  int t = 0;
  funcT(t);
}

Comeau тоже ругается.

error: no instance of function "funcA" matches the argument


Лень рыться в стандарте, но вот что дает поиск:

<quote>
[temp.dep.candidate] 14.6.4.2 Candidate functions
1 For a function call that depends on a template parameter, if the function
name is an unqualified-id but not a template-id, the candidate functions
are found using the usual lookup rules (3.4.1, 3.4.2) except that:
— For the part of the lookup using unqualified name lookup (3.4.1), only
function declarations with external linkage from the template definition
context are found.
— For the part of the lookup using associated namespaces (3.4.2), only
function declarations with external linkage found in either the template
definition context or the template instantiation context are found.
</quote>

"Static functions" have internal, not external linkage, and the function
call depends on template parameter A, so it is an error.


HTH,
--
Michiel Salters


Если добавить явную квалификацию (::funcA(t), то comeau компилит:
Re: Знатокам стандарта
От: Bell Россия  
Дата: 01.07.08 06:16
Оценка: 2 (2)
Здравствуйте, Непомнящий Евгений, Вы писали:

НЕ>Подскажите, должно ли это компилироваться:

НЕ>
НЕ>static void funcA(void *p) {}

НЕ>template<class T>
НЕ>void funcT(T &t)
НЕ>{
НЕ>  funcA(&t);
НЕ>}

НЕ>void test()
НЕ>{
НЕ>  int t;
НЕ>  funcT(t);
НЕ>}
НЕ>


Этот код компилится не должен.
Дело в том, что выражение funcA(&t); является зависимым, и поэтому для поиска имен используются специальные правила, а именно:

14.6.4.2/1 For a function call that depends on a template parameter, if the function name is an unqualified-id but not a
template-id, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2) except that:

— For the part of the lookup using unqualified name lookup (3.4.1), only function declarations with external
linkage
from the template definition context are found.


Поскольку funcA имеет внутреннее связывание, то она как раз подпадает под преведенное выше ограничение, и поэтому не может быть найдена.
Возможно несколько решений проблемы:
1. Убрать static из объявления funcA:
void funcA(void *p) {}


2.Если вариант 1 не устраивает (имя должно быть видимо только в одной еденице трансляции), то поместить funcA в безымянное пространство имен:
namespace
{
   void funcA(void *p) {}
}


3. Зобороть зависимость:
template<class T>
void funcT(T &t)
{
  funcA(static_cast<void*>(&t));
}
Любите книгу — источник знаний (с) М.Горький
Re[2]: Знатокам стандарта
От: Bell Россия  
Дата: 01.07.08 06:22
Оценка:
Здравствуйте, Bell, Вы писали:

Еще один способ (спасибо shank ) :
4.
Сделать квалифицированный вызов:
static void funcA(void *p) {}

template<class T>
void funcT(T& t)
{
  ::funcA(&t);
}

void test()
{
  int t;
  funcT(t);
}


В этом случае ограничения из 14.6.4.2 не работают.
Любите книгу — источник знаний (с) М.Горький
Re[2]: Знатокам стандарта
От: Непомнящий Евгений  
Дата: 01.07.08 06:54
Оценка:
Здравствуйте, Bell, Вы писали:

Спасибо за ответ, побороть-то я и сам поборол — через приведение к void*.
Просто было интересно, почему не работает.

Интуитивно вроде как должно
... << RSDN@Home 1.2.0 alpha 3 rev. 880>>
Re: Знатокам стандарта
От: fGordon Земля  
Дата: 01.07.08 07:22
Оценка:
НЕ>void test()
НЕ>{
НЕ> int t;
НЕ> funcT(t);
НЕ>}

простите за ламмерский вопрос, а разве не надо указать тип?

void test()
{
int t;
funcT<int>(t);
}
in c/c++ we trust!
Re[2]: Знатокам стандарта
От: nrwl  
Дата: 01.07.08 08:43
Оценка:
Здравствуйте, fGordon, Вы писали:

G>простите за ламмерский вопрос, а разве не надо указать тип?


G>void test()

G>{
G> int t;
G> funcT<int>(t);
G>}

Не обязательно. Вроде по 14.7.2

A trailing template-argument can be left unspecified in an explicit instantiation of a function template specialization or of a member function template specialization provided it can be deduced from the type of a function parameter (14.8.2).

Re[2]: Знатокам стандарта
От: Bell Россия  
Дата: 01.07.08 08:45
Оценка:
Здравствуйте, fGordon, Вы писали:

НЕ>>void test()

НЕ>>{
НЕ>> int t;
НЕ>> funcT(t);
НЕ>>}

G>простите за ламмерский вопрос, а разве не надо указать тип?


G>void test()

G>{
G> int t;
G> funcT<int>(t);
G>}

В случае шаблонов функций компилятор в ряде случаев может самостоятельно вывести параметры шаблона.
Любите книгу — источник знаний (с) М.Горький
Re: Знатокам стандарта
От: Erop Россия  
Дата: 02.07.08 12:21
Оценка:
Здравствуйте, Непомнящий Евгений, Вы писали:

НЕ>Подскажите, должно ли это компилироваться:

НЕ>
НЕ>static void funcA(void *p) {}

НЕ>template<class T>
НЕ>void funcT(T &t)
НЕ>{
НЕ>  funcA(&t);
НЕ>}

НЕ>void test()
НЕ>{
НЕ>  int t;
НЕ>  funcT(t);
НЕ>}
НЕ>


А как это должно, по идее, работать?
funcT инстанциируется где попало, из каждой единицы трансляции зовёттся своя funcA... ЧТо-то тут не того...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Знатокам стандарта
От: Непомнящий Евгений  
Дата: 02.07.08 13:04
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Непомнящий Евгений, Вы писали:


E>А как это должно, по идее, работать?

E>funcT инстанциируется где попало, из каждой единицы трансляции зовёттся своя funcA... ЧТо-то тут не того...

Это все сделано локально в одном cpp файле и наружу не торчит. Собственно поэтому и объявил funcA как static.
Возможно, кстати и funcT следовало сделать static...
... << RSDN@Home 1.2.0 alpha 3 rev. 880>>
Re[3]: Знатокам стандарта
От: Erop Россия  
Дата: 02.07.08 13:39
Оценка:
Здравствуйте, Непомнящий Евгений, Вы писали:

НЕ>Это все сделано локально в одном cpp файле и наружу не торчит. Собственно поэтому и объявил funcA как static.

НЕ>Возможно, кстати и funcT следовало сделать static...

а шаблоны так вроде бы не умеют... В смысле "не торчать наружу"
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Знатокам стандарта
От: Непомнящий Евгений  
Дата: 02.07.08 13:51
Оценка:
Здравствуйте, Erop, Вы писали:

E>а шаблоны так вроде бы не умеют... В смысле "не торчать наружу"


template<class T>
static void funcT(T &t)
{
}


На такое компилер не ругается... Я думаю, такая funcT не будет доступна из другой единицы трасляции. Или я не прав?
... << RSDN@Home 1.2.0 alpha 3 rev. 880>>
Re[5]: Знатокам стандарта
От: Bell Россия  
Дата: 02.07.08 14:07
Оценка:
Здравствуйте, Непомнящий Евгений, Вы писали:

НЕ>
НЕ>template<class T>
НЕ>static void funcT(T &t)
НЕ>{
НЕ>}
НЕ>


НЕ>На такое компилер не ругается... Я думаю, такая funcT не будет доступна из другой единицы трасляции. Или я не прав?


Она и без static не будет доступна, если определена в .cpp файле.
Компилятору при испольщовании шаблона требуется его полное определение.
Любите книгу — источник знаний (с) М.Горький
Re[6]: Знатокам стандарта
От: Непомнящий Евгений  
Дата: 02.07.08 14:20
Оценка:
Здравствуйте, Bell, Вы писали:

B>Она и без static не будет доступна, если определена в .cpp файле.

B>Компилятору при испольщовании шаблона требуется его полное определение.

А если я в a.cpp и в b.cpp определю шаблон функции c одним именем и разными телами:
a.cpp:
template<class T>
void func()
{
 a = 10;
}

void f1()
{
  func<int>();
}

b.cpp

template<class T>
void func()
{
 b = 20;
}

void f2()
{
  func<int>();
}


у меня разве не будет ошибки линковки? Компилер же создает на основании шаблона функции имя функции для линкера — вроде как добавляя к имени шаблона имена типов с которыми его инстанцировали. Получится, что у меня две разные функции с одинаковым декорированным именем...
... << RSDN@Home 1.2.0 alpha 3 rev. 880>>
Re[7]: Знатокам стандарта
От: Erop Россия  
Дата: 02.07.08 14:25
Оценка:
Здравствуйте, Непомнящий Евгений, Вы писали:

НЕ>у меня разве не будет ошибки линковки? Компилер же создает на основании шаблона функции имя функции для линкера — вроде как добавляя к имени шаблона имена типов с которыми его инстанцировали. Получится, что у меня две разные функции с одинаковым декорированным именем...


Ошибки линковки может и не быть, но нарушение ODR точно будет
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[7]: Знатокам стандарта
От: Bell Россия  
Дата: 02.07.08 14:33
Оценка:
Здравствуйте, Непомнящий Евгений, Вы писали:


НЕ>у меня разве не будет ошибки линковки?

В случае с шаблонами ошибки линковки не будет, а вот нарушение ODR (и соответственно неопределенное поведение) — будет.
Подробности в 3.2.
Любите книгу — источник знаний (с) М.Горький
Re[3]: Знатокам стандарта
От: Bell Россия  
Дата: 02.07.08 14:39
Оценка:
Здравствуйте, Непомнящий Евгений, Вы писали:

НЕ>Это все сделано локально в одном cpp файле и наружу не торчит. Собственно поэтому и объявил funcA как static.

НЕ>Возможно, кстати и funcT следовало сделать static...

static-функции (в прочем как и переменные) в текущем стандарте поминаются как deprecated (7.3.1.1/2).

Используй безымянные пространства имен, и будет тебе счастье:
namespace
{
   void funcA(void *p) {}

   template<class T>
   void funcT(T &t)
   {
     funcA(&t);
   }
}

void test()
{
  int t;
  funcT(t);
}
Любите книгу — источник знаний (с) М.Горький
Re[2]: Знатокам стандарта
От: Programador  
Дата: 03.07.08 20:13
Оценка:
Здравствуйте, Bell, Вы писали:

B>3. Зобороть зависимость:

B>
B>template<class T>
B>void funcT(T &t)
B>{
B>  funcA(static_cast<void*>(&t));
B>}
B>



долго тупил пока дошло
static void funcA(int *p) {}

template<class T>
void funcT(T &t)
{
  funcA((int *)&t); // тоже нужно
}

void test()
{
  int t;
  funcT(t);
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.