Инстанцирование шаблонных функций. Ошибка при линковке
От: eastmen  
Дата: 29.09.03 10:52
Оценка:
Имеется параметризованный класс.
Для него написаны параметризованные операторы
сравнения. Естественно, они объявлены друзьями
класса, их код идет ниже описания класса.
Компилятор C++Builder 6.0.

Линкер выдает сообщение:
[Linker Error] Unresolved external 'operator <=(fixed_string<char, 51>&, fixed_string<char, 51>&)' referenced from E:\PROJECTS\BCB5\ULBASE\TREPORTREALIZATION.OBJ

Как это побороть.

С уважением Александр
Re: Инстанцирование шаблонных функций. Ошибка при линковке
От: Lorenzo_LAMAS  
Дата: 29.09.03 10:57
Оценка:
Ну так а определения в том же заголовке где и класс? Если нет, то перенеси их туда, если да, то покажи код.
Of course, the code must be complete enough to compile and link.
Re: Инстанцирование шаблонных функций. Ошибка при линковке
От: Аноним  
Дата: 29.09.03 11:19
Оценка:
Возможно, из той же оперы:

template <typename T>
void z(const T t)
{}

template <typename T>
void f(const T t)
{}

int main(int argc, char* argv[])
{
f(z<int>);
return 0;
}



Compiling...
TSpec.cpp
Linking...
TSpec.obj : error LNK2001: unresolved external symbol "void __cdecl z(int)" (?z@@YAXH@Z)
Debug/TSpec.exe : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.

TSpec.exe — 2 error(s), 0 warning(s)

А вот так уже линкуется

template <typename T>
void z(const T t)
{}

template <typename T>
void f(const T t)
{}

int main(int argc, char* argv[])
{
if(0) z<int>(1);
f(z<int>);
return 0;
}


Что с этим делать?
Re: Определения шаблонов
От: eastmen  
Дата: 29.09.03 11:37
Оценка:
Содержимое файла с шаблонами

#ifndef bounded_containers_h
#define bounded_containers_h

#include <stdio.h>
#include <stdlib.h>

template <class data_t = char, int a_size = 64> class fixed_string
{
static long m_size;
long m_length;
data_t m_array[a_size];

public:

explicit fixed_string()
{
m_size = sizeof(m_array)/sizeof(data_t);
m_length = 0;

clear_buffer();
}
//-----------------------------------------------------
void clear()
{
m_array[0] = 0;
}
//-----------------------------------------------------
void clear_buffer()
{
memset(m_array, 0, m_size);
}
//-----------------------------------------------------
data_t *c_str()
{
return m_array;
}
//-----------------------------------------------------
static long size()
{
return (m_size — 1);
}
long length() const
{
return m_length;
}
//-----------------------------------------------------
fixed_string& operator = (fixed_string &rhs)
{
m_length = 0;
data_t *temp_str = rhs.c_str();
long temp_length = rhs.length();

for( ; m_length < temp_length; )
{
m_array[m_length] = temp_str[m_length];
++m_length;
}

m_array[m_length] = 0;

}

//-----------------------------------------------------
fixed_string& operator = (data_t *rhs)
{
long end_position = m_size — 1;
data_t *read_pointer = rhs;

for(m_length = 0; read_pointer[m_length] != 0 &&
m_length < end_position; )
{
m_array[m_length] = read_pointer[m_length];

++m_length ;
}

m_array[m_length] = 0;

return (*this);
}

//-----------------------------------------------------
friend bool operator < (fixed_string &lhs, fixed_string &rhs);

//-----------------------------------------------------
friend bool operator > (fixed_string &lhs, fixed_string &rhs);
//-----------------------------------------------------
friend bool operator <= (fixed_string &lhs, fixed_string rhs);
//-----------------------------------------------------
friend bool operator >= (fixed_string &lhs, fixed_string &rhs);

//-----------------------------------------------------
bool operator == (fixed_string &rhs)
{
if(m_length == rhs.length())
{
return (memcmp(m_array, rhs.c_str(), m_length) == 0);
}
return false;
}
//-----------------------------------------------------
bool operator != (fixed_string &rhs)
{
if(m_length == rhs.length())
{
return !(memcmp(m_array, rhs.c_str(), m_length) == 0);
}

return true;
}

};

/*
template <class data_t, int a_size>
bool operator < (fixed_string<data_t, a_size> &lhs,
fixed_string<data_t, a_size> &rhs)
{
int rc = memcmp(lhs.m_array, rhs.c_str(),min(lhs.length(), rhs.length()));

if(rc < 0)
{
return true;
}
else if (rc == 0)
{
if(lhs.length() < rhs.length())
{
return true;
}

return false;
}

return false;

}

//-----------------------------------------------------
template <class data_t, int a_size>
bool operator > (fixed_string<data_t, a_size> &lhs,
fixed_string<data_t, a_size> &rhs)
{
int rc = memcmp(lhs.m_array, rhs.c_str(),min(lhs.length(), rhs.length()));

if(rc > 0)
{
return true;
}
else if (rc == 0)
{
if(lhs.length() > rhs.length())
{
return true;
}

return false;
}

return false;

}
//-----------------------------------------------------
template <class data_t, int a_size>
bool operator <= (fixed_string<data_t, a_size> &lhs,
fixed_string<data_t, a_size> &rhs)

{
int rc = memcmp(lhs.m_array, rhs.c_str(),min(lhs.length(), rhs.length()));

if(rc < 0)
{
return true;
}
else if (rc == 0)
{
if(lhs.length() <= rhs.length())
{
return true;
}

return false;
}

return false;

}
//-----------------------------------------------------
template <class data_t, int a_size>
bool operator >= (fixed_string<data_t, a_size> &lhs,
fixed_string<data_t, a_size> &rhs)
{
int rc = memcmp(lhs.m_array, rhs.c_str(),min(lhs.length(), rhs.length()));

if(rc > 0)
{
return true;
}
else if (rc == 0)
{
if(lhs.length() >= rhs.length())
{
return true;
}

return false;
}

return false;

}

#endif // bounded_containers_h
Re[2]: Инстанцирование шаблонных функций. Ошибка при линковк
От: Lorenzo_LAMAS  
Дата: 29.09.03 11:47
Оценка:
Так если это VC, то тогда да, он такое не любит fun(z<int>) — объявляй тогда указатель на функцию, либо явно инстанцируй
Of course, the code must be complete enough to compile and link.
Re[2]: Определения шаблонов
От: Lorenzo_LAMAS  
Дата: 29.09.03 11:52
Оценка:
Так как ты объявляешь друзей, другом ты объявляешь НЕ функцию шаблон.
Of course, the code must be complete enough to compile and link.
Re[3]: Определения шаблонов
От: Lorenzo_LAMAS  
Дата: 29.09.03 12:03
Оценка:
Короче, так как это у тебя BCC 5.6, то можно написать так
template<class T1>
friend bool operator < (fixed_string<T1> &/////

Либо так

Объявить предварительно оператор <
template<class T>class fixed_string;

template<class T>bool operator <(/////)

template<class T>class fixed_string
{
friend bool operator < <T> (/////);
};

template<class T>
bool operator< (////)
Of course, the code must be complete enough to compile and link.
Re[3]: Определения шаблонов
От: eastmen  
Дата: 29.09.03 12:39
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>Так как ты объявляешь друзей, другом ты объявляешь НЕ функцию шаблон.


Не понял. Что, нельзя объявить другом
класс-шаблона функцию-шаблон.?

Кстати, это тоже не компилируется.

template <class data_t, int size = 1> class foo
{
friend bool operator < <data_t, size>
(foo<data_t, size>& , foo<data_t, size>&);

};

template <class data_t, int size> bool operator <
(foo<data_t, size>& o_0, foo<data_t, size>& o_1)
{
return true;
}

int main()
{
foo<char, 2> o_0, o_1;

if(o_0 < o_1)
{
return 0;
}

return 1;
}
Re[4]: Определения шаблонов
От: Lorenzo_LAMAS  
Дата: 29.09.03 12:49
Оценка:
Я тебе не говорил, что функцию шаблон нельзя объявить другом. Я сказал, что другом ты объявляешт не функцию шаблон (в твоем исходном примере). Затем я описал, как можно решить твою проблему. Что непонятно?

template<class T>
class A
{
     friend void fun(A);
}


Здесь другом объявлена не функция шаблон. Т.е. для класса A<int> другом будет функция fun(A<int>) и т.д. — их определений-то и нету у тебя. Если б ты, допустим, еще определил друга в классе А (так, как это сделано у тебя) — то это тоже РЕШИТ твою проблему
Of course, the code must be complete enough to compile and link.
Re[5]: Определения шаблонов
От: Lorenzo_LAMAS  
Дата: 29.09.03 12:54
Оценка:
L_L>Здесь другом объявлена не функция шаблон. Т.е. для класса A<int> другом будет функция fun(A<int>) и т.д. — их определений-то и нету у тебя. Если б ты, допустим, еще определил друга в классе А (так, как это сделано у тебя) — то это тоже РЕШИТ твою проблему
template<class T>class A
{
     friend void fun(A<T>)
     {
     }
};

Я имел в виду такое.
Of course, the code must be complete enough to compile and link.
Re[4]: Определения шаблонов
От: Lorenzo_LAMAS  
Дата: 29.09.03 12:56
Оценка:
Здравствуйте, eastmen, Вы писали:

E>Кстати, это тоже не компилируется.

E>template <class data_t, int size = 1> class foo
E>{
E>friend bool operator <  <data_t, size> 
E>          (foo<data_t, size>& , foo<data_t, size>&);

E>};


А предварительные объявления, как в моем примере, ты делал? Если что-то не компилится, ты б хоть текст сообщений приводил. Такое компилиться должно, если только в BCC нет глюков с друзьями
Of course, the code must be complete enough to compile and link.
Re[3]: Инстанцирование шаблонных функций. Ошибка при линковк
От: Аноним  
Дата: 29.09.03 13:11
Оценка:
L_L>Так если это VC, то тогда да, он такое не любит fun(z<int>) — объявляй тогда указатель на функцию, либо явно инстанцируй

Да, это MSVC 6
так тоже не линкуется

template <typename T>
void z(const T t)
{}

template <typename T>
void f(const T t)
{}

//Instantiate z with the explicitly specified template
//argument ‘int’
template void z<int> (int);

int main(int argc, char* argv[])
{
f(z<int>);
return 0;
}

TSpec.obj : error LNK2001: unresolved external symbol "void __cdecl z(int)" (?z@@YAXH@Z)
Debug/TSpec.exe : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.

TSpec.exe — 2 error(s), 0 warning(s)

пробовал
(void)(z<int>);
(void*)(z<int>);
(void*)(&z<int>);
void(*pz)(const int) = &(z<int>);
всё равно не помогает, некоторые даже не компилируются.
спасает только
if(0) z<int>(1);
и
int void(*pz)(int)
pz = z<int>;

Откуда растут ноги:
в некоторые места(шаблоны) нужно передавать функторы —
можно передать либо класс, в котором есть operator() или функцию (её адрес).
Всё было нормально до тех пор, пока я не попытался передать туда инстанциированную шаблонную функцию.
Может это потому, что шаблонная функция не может быть параметром шаблона (могу наврать, но что-то подобное есть в стандарте).
Но я ведь передаю туда её конкретный "инстанс".
Это следствие стандарта или просто глюк VC6?
Re[4]: Инстанцирование шаблонных функций. Ошибка при линковк
От: Lorenzo_LAMAS  
Дата: 29.09.03 13:20
Оценка:
Черт, возможно, мне такое в VC 7.0 помогало.
Of course, the code must be complete enough to compile and link.
Re[4]: Инстанцирование шаблонных функций. Ошибка при линковк
От: Lorenzo_LAMAS  
Дата: 29.09.03 13:24
Оценка:
Впрочем это твоя ошибка:


А>template <typename T>
А>void z(const T t)
А>{}

А>template <typename T>
А>void f(const T t)
А>{}

template void z(const int);

А>int main(int argc, char* argv[])
А>{
А>f(z<int>);
А>return 0;
А>}
Of course, the code must be complete enough to compile and link.
Re[5]: Инстанцирование шаблонных функций. Ошибка при линковк
От: Аноним  
Дата: 29.09.03 13:56
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>Впрочем это твоя ошибка:



А>>template <typename T>
А>>void z(const T t)
А>>{}

А>>template <typename T>
А>>void f(const T t)
А>>{}

L_L>template void z(const int);

А>>int main(int argc, char* argv[])
А>>{
А>>f(z<int>);
А>>return 0;
А>>}


Да, так слинковалось.
А линкер, редиска, ругался так:
TSpec.obj : error LNK2001: unresolved external symbol "void __cdecl z(int)" (?z@@YAXH@Z)

там ничего про const не писалось.
Но это всё равно не спасает — я понаделал макросов, которые добавляют if(0) { ... }
А хотелось бы красиво, как надо
Re[6]: Инстанцирование шаблонных функций. Ошибка при линковк
От: Lorenzo_LAMAS  
Дата: 29.09.03 14:03
Оценка:
У вижуала есть еще одна интересная особенность — он позволяет явно инстанцировать несуществующие функции — что и продемонстрировал твой пример. Кроме того, мне кажется, что писать явное инстанцирование получше, чем макросы и if(0)....
Of course, the code must be complete enough to compile and link.
Re[7]: Инстанцирование шаблонных функций. Ошибка при линковк
От: Аноним  
Дата: 29.09.03 14:55
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>У вижуала есть еще одна интересная особенность — он позволяет явно инстанцировать несуществующие функции — что и продемонстрировал твой пример.

Думаю, здесь всё честно — попросили инстанциировать, значит он её сгенерил. Она легла в соответствующий obj файл. Что значит несуществующие?

L_L>Кроме того, мне кажется, что писать явное инстанцирование получше, чем макросы и if(0)....

Эти вызовы разбросаны по всему проекту, и мне не очень хочется вручную вычислять, какие функции и с какими параметрами мне надо инстанциировать. К тому же сам вызов содержится внутри макроса. Проще вставить if(0) { вызов функции } и пусть компилятор потом ищет, на кого ссылались. Вставить в макрос явное инстанциирование нельзя — макрос используется внутри функций и template там писать нельзя.
Единственный минус — пришлось сделать два типа макросов — там где функтор это функция и там где функтор это объект. Придумать для них код, годный и для функции и для объекта и вызывающий инстанциирование функции я не смог.
Re[8]: Помогло... Отчасти.
От: eastmen  
Дата: 30.09.03 05:28
Оценка:
Объявить предварительно оператор <
template<class T>class fixed_string;

template<class T>bool operator <(/////)

template<class T>class fixed_string
{
friend bool operator < <T> (/////);
};

template<class T>
bool operator< (////)


Данный вариант с предварительным
объявлением операторов привел к положительному
результату, то есть сборка прошла успешо. Но...
Теперь появилась ошибка времени выполнения
"Integer Overflow", за ней другая и программа
кончает свою жизнь. Кроме того в отладчике
после установки точки останова на строку с выражением,
содержащим вызов оператора, отладчик попадает
совсем в другое место текста программы.
Это что, ошибка при генерации кода шаблона
или надо в настройках среды BCB 6 задавать
какой-то параметр.

С уважением Александр.
Re[8]: Инстанцирование шаблонных функций. Ошибка при линковк
От: Lorenzo_LAMAS  
Дата: 30.09.03 06:58
Оценка:
А>Думаю, здесь всё честно — попросили инстанциировать, значит он её сгенерил. Она легла в соответствующий obj файл. Что значит несуществующие?
Я имею в виду следующее.

template<class T>
class A
{
    void fun(T)const
    {
    }
};

template void A<int>::fun();

int main()
{

    return 0;
}
Of course, the code must be complete enough to compile and link.
Re[9]: Помогло... Отчасти.
От: Lorenzo_LAMAS  
Дата: 30.09.03 07:03
Оценка:
E>Данный вариант с предварительным
E>объявлением операторов привел к положительному

Естественно, так как это правильная программа. Правда БЦЦ мог бы и не скомпилировать ее по какой-нить причине, например другой вариант
template<class T>
class A
{
    template<class T>friend void fun(A<T>);
}


Приводит к Internal Compiler Error — и тут уж похоже ничего не сделаешь

E>Теперь появилась ошибка времени выполнения

E>"Integer Overflow", за ней другая и программа
E>кончает свою жизнь.

Я так понимаю, что к исходному вопросу про объявление друзей это уже не имеет отношения

Кроме того в отладчике
E>после установки точки останова на строку с выражением,
E>содержащим вызов оператора, отладчик попадает
E>совсем в другое место текста программы.

Опиши подробней. Я БЦЦ воспользовался только чтоб проверить, что он компилирует, а что нет.
Of course, the code must be complete enough to compile and link.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.