Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Последние темы форума

Показать новые сообщения »

Почтовая рассылка

Подписчиков: 6461
Последний выпуск: 19.06.2015

"LNK2019 ссылка на неразрешенный внешний символ" при вызове констуктора класса из статичной библиотеки.

9.7K
18 августа 2012 года
Vitamant
228 / / 07.02.2011
Консольное приложение обращается к конструктору класса, объявленному в статичной библиотеке.
При компиляции получаю ошибку:
 
Код:
error LNK2019: ссылка на неразрешенный внешний символ "public: __thiscall MyNamespace::System::NArray<int>::NArray<int>(int)" (??0?$NArray@H@System@MyNamespace@@QAE@H@Z)
Хочу заметить, что использование других классов из этой библиотеки проходит нормально, проблема только в этом (вероятно, допущена ошибка, но из-за шаблонов студия не может её корректно обработать).
Код:
// Array.h

#pragma once

#include "Object.h"
#include "String.h"

namespace MyNamespace{
namespace System
{
    template <typename T>
    class NArray : public NObject
    {
    public:
        NArray(int);
        NString ToString();
    };
}}
Код:
// Array.cpp
#include "Array.h"

namespace MyNamespace{
namespace System
{
    template<typename T>
    NArray<T>::NArray(int lenght)
    {
    }

    template<typename T>
    NString NArray<T>::ToString()
    {
        return NString(*this);
    }
}}
263
18 августа 2012 года
arrjj
1.7K / / 26.01.2011
AFAIK Шаблоны так использовать нельзя. Шаблоны преобразуются в классы на этапе компиляции - если в библиотеке нет NArray<int> , то ты его использовать не сможешь
9.7K
18 августа 2012 года
Vitamant
228 / / 07.02.2011
Прошу прощения, верно ли я понимаю, что в С++ нету никакого аналога Generic-типов?
И если я хочу написать тип Array, который может содержать 30 различных типов, я должен создать Array<Type1>, Array<Type2>, ... Array<Type30>?

А как же тогда реализован... тот же std::vector<T>?

Если это так... я явно заблудился и зашёл не туда. Прощай, странный язык, я возвращаюсь в C#...
263
18 августа 2012 года
arrjj
1.7K / / 26.01.2011
Это шаблоны. Каждый раз когда ты обьявляешь std::vector<какойтотип> a; компилятор создаёт конкретный класс std::vector<какойтотип> на этапе _компиляции_. В рантайме так сделать нельзя. А вообще скинь конкретный пример посмотреть.
9.7K
18 августа 2012 года
Vitamant
228 / / 07.02.2011
Так вот же он - вверху.
И вызываю соответственно:

 
Код:
#include "System/Array.h"

using namespace MyNamespace::System;

int main(int count, char** args)
{
  int size = 10;
  NArray<int> arr(size); // тут всё и падает
}
Насчёт вектора - мне это уже пытались объяснить. Не понял. У меня есть .h файл с объявлением (см. выше). У меня есть .cpp файл с реализацией (см. выше). При компиляции, всё это должно собраться и необходимые классы на основе шаблонов - создаться. Причём тут рантайм?..

А вот в .hpp реализацию я вынести не могу, потому что у меня циклические зависимсоти между несколькими h-файлами.
263
18 августа 2012 года
arrjj
1.7K / / 26.01.2011
NObject покажи - в нём проблема. А про рантайм забудь я чет не прочитал что у тебя статик библиотека, думал динамик.

ПыСы. циклические зависимости рашаются следующим кодом:
 
Код:
#ifndef MY_H_FILE
#define MY_H_FILE
//...блаблабла
#endif
но вообще правильно - реализация должна быть в .cpp в .h только объявления
9.7K
18 августа 2012 года
Vitamant
228 / / 07.02.2011
Код:
// Object.h

#pragma once

namespace MyNamespace{
namespace System
{
    class NString;
    class NObject
    {
    public:
        virtual NString ToString() = 0;
    };
}}
Кстати, #pragma once, как я понимаю. выполняет те же функции, что и #define с #ifdef. Вот только если я здесь сдлеаю #include "String.h" а в String.h - #include "Object.h", то получу кучу разномастных ошибок. Пришлось писать вместо инклюда class NString;.

---

Уверен, что в NObject? От него наследуются и другие классы и они создаются нормально. Проблема только в NArray<T>
248
18 августа 2012 года
Ramon
1.1K / / 16.08.2003
Задайтесь вопросом кто, где и по какому принципу инстанциирует конструктор NArray.

PS: Впрочем как и ToString у все того же NArray.
9.7K
18 августа 2012 года
Vitamant
228 / / 07.02.2011
Никто и нигде, коме вышеозначенного места в main.
248
19 августа 2012 года
Ramon
1.1K / / 16.08.2003
Цитата: Vitamant
Никто и нигде, коме вышеозначенного места в main.


Ответ верен, лишь наполовину, ибо main, в данном случае, так же не инстанциирует ни конструктор, ни ToString.

9.7K
19 августа 2012 года
Vitamant
228 / / 07.02.2011
[UPD]Стоп! Тоесть, всё это безобразие у меня используется в библиотеке. Нигде внутри нее я NArray<int> не вызываю. Соответственно, при компиляции, класс NArray<int> на основе шаблона не создаётся. И при попытке вызвать его из кода, использующего эту библиотеку, я не нахожу нужного класса. Верно?

-------------

В таком случае, не осознаю глубинного смысла слова "инстанциирует". Для меня это - создание экземпляра объекта. И NArray<int> arr(size); как раз оно и есть. Что же понимается под "инстанциирует конструктор" мне даже страшно представить.

...или имелось ввиду "вызов функции у экземпляра объекта"? Тогда я очень плохо представляю - как должен быть вызван конструктор уже созданного экземпляра...

В общем, проблема всё ещё актуальна. =\
9.7K
19 августа 2012 года
Vitamant
228 / / 07.02.2011
Ага. Весело. Вынес реализацию в .hpp. Всё скомпилировалось. Теперь нужно в NString использовать NArray, а в NArray - NString.
Тупик? Решения нет? #ifndef и #pragma once не помогают...

Как только появляются взаимные инклюды - компилятор умирает.
248
19 августа 2012 года
Ramon
1.1K / / 16.08.2003
Цитата: Vitamant
Ага. Весело. Вынес реализацию в .hpp. Всё скомпилировалось. Теперь нужно в NString использовать NArray, а в NArray - NString.
Тупик? Решения нет? #ifndef и #pragma once не помогают...

Как только появляются взаимные инклюды - компилятор умирает.


Буквы в студию.

9.7K
19 августа 2012 года
Vitamant
228 / / 07.02.2011
 
Код:
Ошибка    1   error C2027: использование неопределенного типа "MyNamespace::System::NString"
Ошибка    2   error C2027: использование неопределенного типа "MyNamespace::System::NString"
Ошибка    3   error C2027: использование неопределенного типа "MyNamespace::System::NString"
Ошибка    4   error C2143: синтаксическая ошибка: отсутствие ";" перед "<"
Ошибка    5   error C4430: отсутствует спецификатор типа - предполагается int. Примечание. C++ не поддерживает int по умолчанию
Ошибка    6   error C2238: непредвиденные лексемы перед ";"
Код:
// Object.h

#pragma once

namespace MyNamespace{
namespace System
{
    class NString;
    class NObject
    {
    public:
        virtual NString ToString() = 0;
    };
}}
Код:
// Array.hpp

#pragma once

#include "Object.h"
#include "Int32.h"
#include "String.h"

namespace MyNamespace{
namespace System
{
    template <typename T>
    class NArray : public NObject
    {
    public:
        NArray()
        {
        }

        NArray(int lenght)
        {
        }

        NString ToString()
        {
            return NString(*this);
        }
    };
}}
Код:
// String.h

#pragma once

#include "Object.h"
#include "Array.hpp"

namespace MyNamespace{
namespace System
{
    class NString : public NObject
    {
    public:
        NString(void);
        NString(NObject&);
        NString ToString();
    private:
        NArray<int> _buff;
        int lenght;
    };
}}
263
19 августа 2012 года
arrjj
1.7K / / 26.01.2011
NString * ToString(); <- так надо делать. это тебе плюсы, а не решетка. т.е.
Так нельзя:
 
Код:
class A;
class B
{
A foo();
}
А так можно:
 
Код:
class A;
class B
{
A* foo();
}
9.7K
19 августа 2012 года
Vitamant
228 / / 07.02.2011
Плюсы или решётка, а вот что возвращать - объект, ссылку или указатель решать мне. ;)
Ссылку я вернуть не могу, так как объект временный.
Указатель я возвращать не буду, так как освобождать человек должен только то, что он создал самостоятельно.

По части class A; class B; Можно тоже самое с шаблонами?
Сей спидхак я опробовал - либо неопределен T (как у тебя), либо, если добавить {} - двойное объявление шаблона.
Вот такие пироги.

(Ну и если уж возвращать указатель, то std::shared_ptr, а не * :))
263
19 августа 2012 года
arrjj
1.7K / / 26.01.2011
Цитата: Vitamant
Плюсы или решётка, а вот что возвращать - объект, ссылку или указатель решать мне. ;)



Компилятор тебе не даст вернуть неполный тип. Ему нужно знать размер объекта чтоб его вернуть а размер NObject неузнаешь пока не получишь размер NString, размер которого не узнаешь пока не получишь размер NObject ....а вот размер указателя он прекрасно знает.

9.7K
20 августа 2012 года
Vitamant
228 / / 07.02.2011
Ага. Вот в чём суть. Понятно. Окей, попробуй перевести на shared_ptr. Посмотрим, что будет.

P..S. Всю свою программерскую жизнь я только и слышал о том, какой гибкий С++ и как ограничены все прочие языки в сравнении с ним. И вот результат. В кои то веки нашёл время заняться освоением С++ и за один день набрал столько минусов, что хочется забыть о нём, как о страшном сне и вернуться к родным C# и ассёмблеру.
263
20 августа 2012 года
arrjj
1.7K / / 26.01.2011
Цитата: Vitamant

P..S. Всю свою программерскую жизнь я только и слышал о том, какой гибкий С++ и как ограничены все прочие языки в сравнении с ним.


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

Цитата: Vitamant
В кои то веки нашёл время заняться освоением С++ и за один день набрал столько минусов, что хочется забыть о нём, как о страшном сне и вернуться к родным C# и ассёмблеру.


Да лааадно... какие? Шаблоны из библиотеки? Потому что это библиотеки, а не шарповские "сборки". Нельзя вернуть неполный тип? В шарпе вообще всё обращение к объектам идет по хендлам в кучу, за которой следит сборщик мусора. Ну а вообще проблема заключается в том, что ты хочешь писать на C++ как на C# - это разные вещи, просто прими это.

9.7K
20 августа 2012 года
Vitamant
228 / / 07.02.2011
Да вот пытаюсь его принять, а он сопротивляется. :)

Основные претензии в общем-то не столько к самому С++, сколько к компиляторам и линкерам. Инлюкды ему пропиши. Либы ему пропиши. Подкаталоги он не видит. В коде #pragma once / #ifndef втыкай (а то бестолковый компилятор не знает, что один файл нужно скомпилировать один раз, а не 100500). Можно сделать кучу ошибок (по неопытности, невнимательности), а он скомпилит и не почешется. Зато укажешь где-нибудь неверное имя типа, а он тебе десяток ошибок - не то, что ни на эту строчку, а вообще в другом файле укажет. Интелесенс нормальный только в 2012ой студии появился. В общем... кошмар.

(Возможно, в каких-нибудь Eclipse + clang или Qt + gcc всё иначе, но увы - билдить приходится в студии)

Знаете кого-то, кто может ответить? Поделитесь с ним ссылкой.

Ваш ответ

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог