[c++] Проблема при линковке - unresolved variable

internet-mail

Я использую MSVC-компилятор. Определяю в одном файле (name.h) некоторый шаблонный класс, далее в другом файле (name.cpp) определяю функцию-член определенного ранее класса, которую вызываю в третьем файле (main.cpp). При линковке возникает ошибка LNK2001 - unresolved variable 'имя_функции-члена_моего_класса '.... Кто знает, что делать в таком случае? Я уж даже не знаю - вроде вcе правильно делаю...

tamusyav

Код, пожалуйста. Если он говорит, что unresolved variable, то мне кажется, что у тебя что-то не так с синтаксисом.

internet-mail

Вот код:
name.h
#ifndef NAME_H
#define NAME_H
template <class DATA> class CLASS_NAME{
     public:
    void Func;
};
#endif
name.cpp
#include "name.h"
template<class DATA> void CLASS_NAME<DATA>::Func
{
}
main.cpp
#include "name.h"
class data{
     public:
    doouble x;
};
int main{
  CLASS_NANE<data> ob;
  ob.Func;
  return 0;
}
 

yolki

CLASS_NANE

internet-mail

Блин, ошибочка вышла. Со спеллингом все нормально - я проверял, это когда пост писал очепятался

evgen5555

Ну, а ошибка какая вылезает?

internet-mail

Ошибка такого типа:
unresolved variable - template<class data> void CLASS_NAME<data>::Func
кажется так...

ppplva

То, что ты пытаешься сделать, называется экспортом шаблонов. Он не реализован в твоем компиляторе.

internet-mail

Это, что, тогда получается в своем шаблонном классе я не смогу определить ни одной функции-члена данного шаблонного класса? Тогда зачем мне такой класс? Это как-то странно выглядит... Неужели совсем ничего нельзя сделать?

ppplva

Можно в хедер перенести.

internet-mail

Вау! Точно,это помогает! Спасибо большое!

tamusyav

Проблема в том, что при компиляции name.cpp компилятор не знает, под какие типы надо инстанцировать класс и, соответственно, его метод, поэтому не инстанцирует никакого. А при компиляции main.cpp он вообще не встречает исходного текста этого метода, что вполне естественно, но итогом является то, что в итоге Func вообще не компилируется.
Вывод: либо весь шаблонный класс вместе с методами должен располагаться в h-файле (и, соответственно, содержать только inline-методы либо использовать явную инстанциацию (и ограничиться фиксированным набором значений аргументов шаблона либо использовать компилятор с поддержкой экспорта шаблонов, либо не использовать здесь шаблонный класс.

erotic

либо весь шаблонный класс вместе с методами должен располагаться в h-файле (и, соответственно, содержать только inline-методы)
Это не связанные вещи. Т.е. описание шаблонной функции должно быть в хедере, но при этом она не обязана быть inline, если ты ее таковой не объявишь.

tamusyav

Да, но если этот файл включается более, чем в одном месте, при наличии не-inline функций будут проблемы при сборке (если только во всех классах не производится инстанцирование к разным типам, но на это закладываться плохо).

erotic

Ты это говоришь, потому что так думаешь, или потому что у тебя действительно бывали такие проблемы?
Я хочу тебе сказать, что у меня таких проблем со сборкой не было, MSVC8

mira-bella

Это не связанные вещи. Т.е. описание шаблонной функции должно быть в хедере, но при этом она не обязана быть inline, если ты ее таковой не объявишь.
1. если функция определена в теле класса, то она автоматически является inline (по стандарту)
2. функция определенная вне тела класса не будет конечно inline, если ее не объявить таковой.
3. функция определенная в хедере по стандарту обязана быть inline (т.е. прогер должен явно или неявно объявить ее таковой в противном случае при включении данного хедера в разные трансляции нарушается "one definition rule". (это может приводить или не приводить к проблеме в зависимости от компилятора или версии оного)

mira-bella

То, что ты пытаешься сделать, называется экспортом шаблонов. Он не реализован в твоем компиляторе.
это называлось бы экспортом шаблонов, если бы перед определением функции-члена стояло ключевое слово export, а так это называется просто ошибка (не синтаксическая ошибка, а просто функция доступна только в той трансляции, в которой определена, а используется в другой трансляции - и это так и должно быть и с точки зрения стандарта языка и с точки зрения большинства компиляторов).

erotic

Каким образом оно нарушается, если объявления буква в букву повторяются?

tamusyav

А почему, собственно, обязательно повторяются? Теоретически они могут оказаться различными. А компилятор не обязан их сравнивать.
Кстати, MSVC8 на это дело ругается. Только что проверял.

erotic

А почему, собственно, обязательно повторяются?
Мы сейчас говорим о том, что ты определяешь тело шаблонной функции или класса в хедере. Если при этом ты включаешь хедер в различные единицы трансляции, у тебя содержание хедера каждый раз будет произвольно меняться? Думаю, что нет.

tamusyav

Почему бы и нет? Макросы никто не отменял.

erotic

Кстати, MSVC8 на это дело ругается. Только что проверял
На какое дело? На определение шаблонной функции в хедере? А разве не писал, что у него работает?

kokoc88

Кажется, функция не обязана являться inline. Она может быть локально вкомпилирована в каждый объектный файл в виде отдельной функции. Но это техника, конечно.

erotic

Хм. Конечно, не отменял.
Вообще-то, я сейчас говорю о том, что если специально это правило не нарушать, то оно не нарушается, и вполне стандартным является объявление не инлайн шаблонных функций в хедере.
То, что ты говоришь о макросах - естественно, что если ты хочешь создать себе проблем, то ты найдешь способ это сделать.

tamusyav

Ругается на определение не-inline функции в хедере, который включен в нескольких файлах. У -а, небось, он включен только в один файл, или описание размещено в теле класса.

tamusyav

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

mira-bella

Каким образом оно нарушается, если объявления буква в букву повторяются?
вообще-то ты прав - не нарушается
думал, что нарушается согласно пункту 3 (который касается как выяснилось только обычных функций, а не шаблонных но потом увидел, что согласно пункту 5 функции-члены шаблонных классов могут быть определены в разных трансляциях (одинаково).

kokoc88

Странно, у меня не ругается. А как ты написал?

tamusyav


testclass.h
class A {
void func;
};
void A::func
{
}
//----------------------
hTest.cpp
#include "testclass.h"
int main
{
return 0;
}
//----------------------
other.cpp
#include "testclass.h"

erotic

Попробуй собрать это, если тебе, конечно, не влом:
template.h
 template <typename T>
T echo(T var)
{
return var;
}

double_echo.h
 int double_echo(int var); 

double_echo.cpp
 #include "double_echo.h"
#include "template.h"
int double_echo(int var)
{
return echo(var);
}

test.cpp
 #include <iostream>
#include "template.h"
#include "double_echo.h"
using namespace std;
int main
{
int a = 0, b;
b = echo(a);
if (b == double_echo(a
cout << "I am a luser";
else
cout << "I am lucky";
}

erotic

И где у тебя testclass.h описан?

erotic

нестатические функции-члены шаблонных классов могут быть определены в разных трансляциях (одинаково)
Хм, а как тогда быть со статическими шаблонными членами?

tamusyav

Пардон, опечатался. Первый файл не cpp, а h

erotic

Мне кажется, ты ошибаешься насчет статических функций, потому что вот:
template.h
 template <typename T>
class ZZ
{
public:
static T echo(T var);
};
template <typename T>
T ZZ<T>::echo(T var)
{
return var;
}

double_echo.h
 int double_echo(int var); 

double_echo.cpp
 #include "double_echo.h"
#include "template.h"
int double_echo(int var)
{
return ZZ<int>::echo(var);
}

test.cpp
 #include <iostream>
#include "template.h"
#include "double_echo.h"
using namespace std;
int main
{
int a = 0, b;
b = ZZ<int>::echo(a);
if (b == double_echo(a
cout << "I am a luser";
else
cout << "I am lucky";
}

Собирается, запускается, работает.

erotic

Лол, у тебя класс не шаблонный.

mira-bella

Кажется, функция не обязана являться inline. Она может быть локально вкомпилирована в каждый объектный файл в виде отдельной функции. Но это техника, конечно.
я использую термин inline-функция как термин из стандарта
так вот: как inline-функция, так и не-inline-функция может быть как локально вкомпилирована в каждый объектник (или только в один объектник так и быть встроена в место ее использования - это зависит исключительно от реализации.
Является ли она inline или нет определяется исключительно синтаксисом ее объявления и определения, а не тем куда она вкомпилирована.
Это не предмет дискуссии, а просто терминология такая (из стандарта ISO/IEC-14882).

mira-bella

Хм, а как тогда быть со статическими шаблонными членами?
да так же
написано просто "member function of a class template"
это я просто сослался на данную конкретную ситуацию, но для большей общности подредактировал тот пост (убрал слово "нестатические")

mira-bella

Мне кажется, ты ошибаешься насчет статических функций,
я не могу насчет них ошибаться, поскольку я насчет них ничего не утверждал
уже я пост поправил
Собирается, запускается, работает.
наверно ты и сам догадываешься насколько это наивно приводить в качестве аргумента.
я могу такие кошмарные проги, которые "работают" (на конкретном компиляторе) привести, что офигеешь.
Работающие проги, и корректные согласно стандарту проги - это совсем разные вещи (общеизвестны примеры как работающих, но некорректных, так и корректных, но неработающих).
А уж когда речь о таких тонких материях как соответствие "one definition rule", диагностика которого стандартом вообще не требуется (т.е. все может оказаться целиком на совести программиста в полном соответствии со стандартом то тем более.

erotic

Угу, согласен.

mira-bella

А почему, собственно, обязательно повторяются? Теоретически они могут оказаться различными. А компилятор не обязан их сравнивать.
вот если определения одной и той же функции (шаблонной или inline) окажутся разными в разных трансляциях - это и будет нарушением "one definition rule", а если определения одной и той же функции синтаксически идентичны, то нарушения нет.
И да: компилятор не обязан диагностировать (замечать) нарушение "one definition rule", соблюдение оного - обязанность программиста.
Нарушение "one definition rule" может не приводить к проблемам, может вызывать ошибку, а может приводить к очень экзотическим проблемам с неожиданными проявлениями (все от реализации зависит).
Оставить комментарий
Имя или ник:
Комментарий: