Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.55/11: Рейтинг темы: голосов - 11, средняя оценка - 4.55
2 / 2 / 0
Регистрация: 08.01.2016
Сообщений: 491

Приватная переменная недоступна в шаблонном методе реализованном в .h файле

15.09.2020, 20:47. Показов 2609. Ответов 36

Студворк — интернет-сервис помощи студентам
Добрый вечер,

Есть класс SeisContainer. Этот класс имеет приватную переменную File h5File (File это тип из библиотеки с работой HDF5 форматом данных).
Класс SeisContainer имеет метод createSeis(...). Если реализацию этого метода помещаю в файл .срр то никаких проблем не возникает и все работает, но мне необходимо объявить этот метод как шаблон и соответственно реализацию я помещаю в заголовочный файл. Тогда я получаю ошибку связанную с тем, что File h5File не может создать группу (Group).
Помогите пожалуйста разобраться, где я косячу когда использую шаблон?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class COREDLL_EXPORT SeisContainer
{
private:
    explicit SeisContainer(File &file);
 
public:
    static std::optional<SeisContainer>
    create(File &h5File);
    static std::optional<SeisContainer>
    create(QString fileName, unsigned int openFlags = File::ReadWrite | File::OpenOrCreate);
 
 
//    template <typename trace_T, typename trace_header_T>
    std::optional<Seis> createSeis(
            QString seisName, h5core::H5SeisFlags h5Flags, size_t nTrc, size_t nSamp, size_t trcChunk = 20000);
 
private:
    File h5File;
};
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// приватный конструктор
SeisContainer::SeisContainer(File &h5File):
    h5File(h5File)
{
 
}
 
 
//    template <typename trace_T, typename trace_header_T>
std::optional<Seis> SeisContainer::createSeis(
        QString seisName, h5core::H5SeisFlags h5Flags, size_t nTrc, size_t nSamp, size_t trcChunk){
    Group seisGroup = h5File.createGroup(seisName.toStdString()); // здесь я получаю ошибку если метод шаблонный и реализован в заголовке
 
 
// здесь в теле метода я использую типы typename trace_T, typename trace_header_T
 
    return Seis::create(seisGroup);
}
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
15.09.2020, 20:47
Ответы с готовыми решениями:

Приватная переменная C++ Builder 10.2
Как написать код по этому тексту: &quot;В методе Unit1.cpp (Server): Добавьте к классу TForm1 приватную переменную Strтипа String, в...

Узнать размер типа-параметра в шаблонном методе
Доброе утро! Подскажите, пожалуйста, как по параметру шаблона типа &quot;тип&quot; узнать его размер: public int...

Переменная, содержащая тип, в шаблонном классе
есть некий шаблонный класс. объект класса создается как-то так newtype&lt;int&gt; a; здесь int выступает в качестве типа, который...

36
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
15.09.2020, 23:55
Студворк — интернет-сервис помощи студентам
Сделай пока, чтоб всегда новый создавался
C++
1
2
3
4
5
6
SeisContainer::SeisContainer(QString fileName, unsigned int openFlags)
: h5File(fileName.toStdString(), openFlags)
{
        h5File.createAttribute<int>(std::string("ContainerType"), DataSpace::From(static_cast<int>(h5core::ContainerType::SEISMIC)))
            .write(static_cast<int>(h5core::ContainerType::SEISMIC));
}
1
2 / 2 / 0
Регистрация: 08.01.2016
Сообщений: 491
16.09.2020, 04:08  [ТС]
oleg-m1973,
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Кстати, а ты каждый раз новый файл создаёшь, или открываешь существующий?
Каждый раз новый создаю. В случае ошибки удаляю файл, а затем снова запускаю аппликейшн

Я убрал using namespace HighFive ошибка не ушла.

Цитата Сообщение от oleg-m1973 Посмотреть сообщение
SeisContainer::create тебе вообще не нужна
Мне не очень нравится работать с исключениями, и хотелось бы в случаях, когда не выполняются мои требования, возвращать не SeisContainer, а std::nullopt

Добавлено через 56 минут
oleg-m1973, оставил реализацию в хедере, убрал темплайт и все равно не работает. При этом если реализацию сделать в .срр и убрать темплейт то работает.
Вероятно это никак не связано с темлэйтом, но связано с реализацией в хедере

Добавлено через 2 часа 36 минут
oleg-m1973, я не понимаю почему, но h5File в хедере не работает только с существующим файлом, то есть с тем файлом, который был создан в экземпляре класса SeisContainer. При этом, даже если в хедере h5File присвоить другой уже существующий HDF5 файл (с жесткого диска), то h5File окажется работоспособным.
Опять же, в .срр файле никаких проблем с переменной h5File нет...

Добавлено через 15 минут
oleg-m1973,
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Сделай пока, чтоб всегда новый создавался
Пробовал не помогает. Также пробовал создавать указатель объекта SeisContainer и тоже не помогает. Вообще не понимаю что не так.
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
16.09.2020, 11:53
Цитата Сообщение от Kerim_Geophysic Посмотреть сообщение
Пробовал не помогает. Также пробовал создавать указатель объекта SeisContainer и тоже не помогает. Вообще не понимаю что не так.
В общем, проблема не в том где ты этот метод объявляешь, а в том, что ты как-то неправильно работаешь с этими файлами.
Сделай реализацию своего метода прямо внутри класса, и проверь с шаблонами и без
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class COREDLL_EXPORT SeisContainer
{
private:
    explicit SeisContainer(File &h5File);
 
public:
    static std::optional<SeisContainer>
    create(File &h5File);
 
    ///
    /// \brief create may also create new h5 Seismic file
    /// \param fileName
    /// \param openFlags HighFive openFlags
    /// \return created file
    ///
    static std::optional<SeisContainer>
    create(QString fileName, unsigned int openFlags = File::ReadWrite | File::OpenOrCreate);
 
    std::optional<Seis> getSeis(QString seisName);
 
    //template <typename trace_T, typename trace_header_T>
    std::optional<Seis> SeisContainer::createSeis(QString seisName, h5core::H5SeisFlags h5Flags, size_t nTrc, size_t nSamp, size_t trcChunk = 2000)
    {
        if (hasSeis(seisName))
            return  std::nullopt;
 
        Group seisGroup = h5File.createGroup(seisName.toStdString());
        seisGroup.createAttribute<int>(std::string("SeisDataType"), DataSpace::From(h5Flags.typeFlag.operator int())).
                write(h5Flags.typeFlag.operator int());
        seisGroup.createAttribute<int>(std::string("Domain"), DataSpace::From(h5Flags.domainFlag.operator int())).
                write(h5Flags.domainFlag.operator int());
        seisGroup.createAttribute<int>(std::string("SurveyType"), DataSpace::From(h5Flags.surveyTypeFlag.operator int())).
                write(h5Flags.surveyTypeFlag.operator int());
 
        //createTextHeader(seisGroup);
        //createBinHeader(seisGroup);
        //createTrace<trace_T>(seisGroup, nTrc, nSamp, trcChunk);
        //createTraceHeader<trace_header_T>(seisGroup, nTrc, trcChunk);
        //createBoundary(seisGroup);
        //createSamples(seisGroup, nSamp);
        //createSort(seisGroup);
 
        return Seis::create(seisGroup);
    }
1
2 / 2 / 0
Регистрация: 08.01.2016
Сообщений: 491
16.09.2020, 16:49  [ТС]
oleg-m1973,
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Сделай реализацию своего метода прямо внутри класса, и проверь с шаблонами и без
попробовал, безрезультатно. Может как то загуглить? Я не могу сформулировать вопрос в гугл
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
16.09.2020, 16:57
Цитата Сообщение от Kerim_Geophysic Посмотреть сообщение
попробовал, безрезультатно. Может как то загуглить? Я не могу сформулировать вопрос в гугл
Ошибку возвращает функция H5Gcreate2. Поэтому смотришь https://www.google.com/search?... e&ie=UTF-8
Мне, к сожалению, сложно тебе тут что-то подсказать, т.к. я понятия не имею что это такое
1
2 / 2 / 0
Регистрация: 08.01.2016
Сообщений: 491
17.09.2020, 18:23  [ТС]
oleg-m1973, я прошу прощения снова обращаюсь к вам.
Я заметил, что все указанные проблемы существуют только когда я SeisContainer помещаю в динамическую библиотеку. Например, если упростить класс SeisContainer до одного конструктора:

seiscontainer.h
C++
1
2
3
4
5
6
7
8
9
class COREDLL_EXPORT SeisContainer // COREDLL_EXPORT сообщает Qt что класс включается в динамическую библиотеку
{
public:
    explicit SeisContainer(HighFive::File h5File):
        h5File(h5File)
    {
        int val = h5File.isValid(); // FALSE
    }
}
seiscontainer.cpp
C++
1
#include "seiscontainer.h"
Видите,переменная val = false если добавлена директива COREDLL_EXPORT (если класс включен в динамическую библиотеку. Однако, если убрать эту директиву (не включать класс в бибилиотеку), то val = true

Кроме того, без .срр файла и с COREDLL_EXPORT я получаю ошибки на этапе линковки:
main.obj:-1: ошибка: LNK2019: unresolved external symbol "__declspec(dllimport) public: __cdecl SeisContainer::SeisContainer(class HighFive::File)" (__imp_??0SeisContainer@@QEAA@VFile@High Five@@@Z) referenced in function main
main.obj:-1: ошибка: LNK2019: unresolved external symbol "__declspec(dllimport) public: __cdecl SeisContainer::~SeisContainer(void)" (__imp_??1SeisContainer@@QEAA@XZ) referenced in function main
debug\app.exe:-1: ошибка: LNK1120: 2 unresolved externals

Поэтому я добавляю пустой .срр файл

Таким образом, проблемы берутся оттого, что я включаю класс в динамическую библитеку и реализую методы класса в хэдэр файле.

Может у вас появились новые мысли? Мне не хватает знаний чтобы понять почему так происходит

Работаю в Qt 5.14.2, Windows 10 x64, компилятор MSVC 2017
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
17.09.2020, 18:29
Лучший ответ Сообщение было отмечено Kerim_Geophysic как решение

Решение

Цитата Сообщение от Kerim_Geophysic Посмотреть сообщение
Я заметил, что все указанные проблемы существуют только когда я SeisContainer помещаю в динамическую библиотеку. Например, если упростить класс SeisContainer до одного конструктора:
С этого и надо было начинать.
Классы вообще лучше не использовать в экспорте dll. А шаблонные - тупо нельзя.
Тут надо использовать абстактный интерфейс с виртуальными функциями.
1
2 / 2 / 0
Регистрация: 08.01.2016
Сообщений: 491
17.09.2020, 18:38  [ТС]
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
С этого и надо было начинать.
Классы вообще лучше не использовать в экспорте dll. А шаблонные - тупо нельзя.
Тут надо использовать абстактный интерфейс с виртуальными функциями.
Вот эт да
Это касается только динамической библиотеки или статической тоже?
Можно ссылку где можно про эти нюансы почитать?
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
17.09.2020, 18:53
Цитата Сообщение от Kerim_Geophysic Посмотреть сообщение
Это касается только динамической библиотеки или статической тоже?
Только динамической. Динамическая библиотека - это независимый физический модуль, который может быть создан где угодно и как угодно. Соответственно ограничения.

Добавлено через 3 минуты
Цитата Сообщение от Kerim_Geophysic Посмотреть сообщение
Можно ссылку где можно про эти нюансы почитать?
Мне сложно дать тебе ссылку, я изучал всё это сто лет назад, когда ещё интернета-то толком не было. Почитай что-нибудь про OLE\COM, ну и вообще про dll
1
2 / 2 / 0
Регистрация: 08.01.2016
Сообщений: 491
17.09.2020, 19:02  [ТС]
oleg-m1973, понял, спасибо буду знать!
0
19501 / 10106 / 2461
Регистрация: 30.01.2014
Сообщений: 17,825
18.09.2020, 10:18
Kerim_Geophysic, в рамках одного компилятора Visual Studio (т.е.е если ваши DLL и Приложение созданы одним компилятором) вы можете делать экспорт класса из DLL, но у этих классов не нужно делать inline методы. Это может привести к нарушению ODR.
Шаблоны классов - это вообще не классы, а лишь трафарет для них, поэтому их физически нельзя разместить внутри DLL.

Цитата Сообщение от Kerim_Geophysic Посмотреть сообщение
Кроме того, без .срр файла и с COREDLL_EXPORT я получаю ошибки на этапе линковки
У вас какой-то совершенно дикий пробел в знаниях касательно раздельной компиляции. Это надо срочно исправлять.

Ошибки вы получаете потому, что экспорт класса приводит к экспорту всех его функций, но чтобы экспортировать их, они должны быть физически размещены в модуле. inline-функции физически не существуют, если их никто не вызывает (а этого у вас не происходит на стороне модуля DLL), поэтому в результате вы оставили вашу DLL без определений этих функций.
1
2 / 2 / 0
Регистрация: 08.01.2016
Сообщений: 491
18.09.2020, 17:31  [ТС]
Цитата Сообщение от DrOffset Посмотреть сообщение
Kerim_Geophysic, в рамках одного компилятора Visual Studio (т.е.е если ваши DLL и Приложение созданы одним компилятором) вы можете делать экспорт класса из DLL, но у этих классов не нужно делать inline методы. Это может привести к нарушению ODR.
Шаблоны классов - это вообще не классы, а лишь трафарет для них, поэтому их физически нельзя разместить внутри DLL.
Я понимаю, что я много не знаю о программировании, в основном учусь на ошибках и гуглю возникающие вопросы.
"Негативная" уникальность шаблонов (шаблонные методы/классы) в моем понимании заключается в том, что они должны быть определены в заголовочном файле. Соответственно возникают следующие трудности:
если шаблонный метод требует внешних включений (требует #inline ...), то эти директивы придется включать в этот заголовочный файл (а не в файл реализации как это рекомендуется). Тогда в последующем, когда этот хэдэр с шаблонными методами надо будет включить в другой класс (в другой файл .h/.срр, вероятно это можно назвать "модуль"), то этот хэдэр потащит за собой и все уже включенные в него инклюды. Помимо неудобств, это вроде бы может также приводить к каким-то конфликтам, которые сложно обнаружить и разрешить (пару месяцев назад вроде бы встречался с такой проблемой, что исходный код на этапе сборки стал выдавать ошибку)

Не совсем понимаю сложности с inline методами. Загуглил тут:https://ru.wikipedia.org/wiki/... 0%B8%D1%8F
inline могут работать быстрее, но если рассматривать сборку как препроцессинг, компиляция и линковка, то мне не понятно на каком этапе эти встроенные функции собираются не так как обычные методы.

Цитата Сообщение от DrOffset Посмотреть сообщение
Ошибки вы получаете потому, что экспорт класса приводит к экспорту всех его функций, но чтобы экспортировать их, они должны быть физически размещены в модуле. inline-функции физически не существуют, если их никто не вызывает (а этого у вас не происходит на стороне модуля DLL), поэтому в результате вы оставили вашу DLL без определений этих функций.
Вроде как с 10 раза прочтения до меня дошло. DLL библиотека собирается сама по себе, а inline методы могут быть не собраны (в зависимости от компилятора видимо), и чтобы повысить шансы на то, что встроенная функция будет включена в DLL, надо где-то внутри этой DLL вызвать эту встроенную функцию.
С шаблонами также?
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
18.09.2020, 17:46
Цитата Сообщение от Kerim_Geophysic Посмотреть сообщение
Вроде как с 10 раза прочтения до меня дошло. DLL библиотека собирается сама по себе, а inline методы могут быть не собраны (в зависимости от компилятора видимо), и чтобы повысить шансы на то, что встроенная функция будет включена в DLL, надо где-то внутри этой DLL вызвать эту встроенную функцию.
Функции, которые в длл, работают с кодом который был на момент компиляции этой длл. Если ты при компиляции exe-файла, который использует эту длл, изменишь заголовок или поменяешь какие-то опции компиляторе (всё это надо специально учитывать при декларации общего кода), то exe у тебя будет работать с одним кодом/данными, а dll - с другим. Соответственно всё разъедется.
1
2 / 2 / 0
Регистрация: 08.01.2016
Сообщений: 491
18.09.2020, 18:04  [ТС]
oleg-m1973, вопрос:
обычно для подключения DLL мы включаем необходимые заголовки и подключаем саму библиотеку DLL. Если какая то функция DLL определена в заголовке, то будет ли эта функция включена в DLL? И если да, то наше приложение, использующее DLL, при включении этого заголовка откуда будет брать определение этой функции: из DLL или из хэдэра?
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
18.09.2020, 18:08
Цитата Сообщение от Kerim_Geophysic Посмотреть сообщение
обычно для подключения DLL мы включаем необходимые заголовки и подключаем саму библиотеку DLL. Если какая то функция DLL определена в заголовке, то будет ли эта функция включена в DLL? И если да, то наше приложение, использующее DLL, при включении этого заголовка откуда будет брать определение этой функции: из DLL или из хэдэра?
Из заголовка. И, если оно там будет неправильное, то и работать тоже будет неправильно.

Добавлено через 2 минуты
Из длл ты можешь получить только указатель на функцию, т.е. какой-то адрес. Как его интерпретировать решается уже в exe, ты сам решаешь, грубо говоря вручную
1
2 / 2 / 0
Регистрация: 08.01.2016
Сообщений: 491
18.09.2020, 18:26  [ТС]
oleg-m1973, спасибо большое за разъяснение
немного въехал
0
19501 / 10106 / 2461
Регистрация: 30.01.2014
Сообщений: 17,825
18.09.2020, 20:45
Цитата Сообщение от Kerim_Geophysic Посмотреть сообщение
DLL библиотека собирается сама по себе, а inline методы могут быть не собраны (в зависимости от компилятора видимо), и чтобы повысить шансы на то, что встроенная функция будет включена в DLL, надо где-то внутри этой DLL вызвать эту встроенную функцию.
Если inline-метод не используется, то он не будет создан, это не зависит от компилятора - это везде так.

А вот если вы вызовете эту функцию внутри DLL, то тело ее может быть создано, а может и не быть создано - это вот как раз зависит от компилятора.

Цитата Сообщение от Kerim_Geophysic Посмотреть сообщение
мне не понятно на каком этапе эти встроенные функции собираются не так как обычные методы.
Они "собираются" по месту вызова. Само название inline как бы намекает.

Цитата Сообщение от Kerim_Geophysic Посмотреть сообщение
"Негативная" уникальность шаблонов (шаблонные методы/классы) в моем понимании заключается в том, что они должны быть определены в заголовочном файле.
Ничего тут нет негативного.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
18.09.2020, 20:45

Почему в обработчике кнопки недоступна переменная из Form_Load??
Почему в обработчике кнопки недоступна переменная из Form_Load?? private void Form2_Load(object sender, EventArgs e) {... ...

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

Переменная не работает в другом методе
Есть переменная score. Объявлена в классе. В этом же классе есть два метода. Переменной присваевается значение из второго метода и далее...

Не изменяется глобальная переменная в методе
В методе &quot;loadpt2&quot; заполняю массив потоков. Он по моему глобальный, тогда почему при выходе с метода опять массив этот стает пустым?...

Переменная не увеличивается в статическом методе
Привет народ! я начинающий, помогите плиз. Изучаю односвязные списке, задача состоит в том, что надо создать метод который должен...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
37
Ответ Создать тему
Новые блоги и статьи
сукцессия 14. Обновленная схема модели
anaschu 28.06.2026
ГЛОБАЛЬНАЯ ОПИСАТЕЛЬНАЯ СПЕЦИФИКАЦИЯ ЭКОСИСТЕМНОЙ МОДЕЛИ «SOIL CHEMISTRY & MYCORRHIZA 2. 0» https:/ / ibb. co/ NnkGpfMd Представленная интегрированная схема описывает непрерывную нелинейную. . .
сукцессия 13. Питон модель трехзонного мицелия, пока что в основном арбускулярного
anaschu 28.06.2026
## Разработка агентной модели микоризной сукцессии: от выявления артефактов к созданию комплексной системы ### Аннотация Представлено исследование по разработке агентной модели микоризной. . .
сукцессия 12. краткий список проверок модели перед запуском.
anaschu 27.06.2026
Скрытые отказы в моделях систем динамики (SD-models) экологических систем: два случая из практики Контекст Разбирался прототип модели систем динамики (SD-модели) микоризной сукцессии: пять. . .
Сукцессия 11. Проверка орудий перед войной: разработка через тестирование
anaschu 27.06.2026
Как не дать модели соврать самой себе: проверки для симуляции микоризной сукцессии Введение Когда вы строите математическую модель живой системы — грибов, растений, почвы — главная опасность. . .
10 сукцессия. Питон код войны грибов и растений
anaschu 27.06.2026
import numpy as np class PlantAgent: def __init__(self, name, strategy, initial_biomass): self. name = name self. strategy = strategy # "greedy" (широколиственные) или. . .
сукцессия 9. Математика подлости: как растения предали грибных друзей
anaschu 27.06.2026
Статья 2. Глобальная фосфорная война: эволюционно-экономические механизмы распределения биомов Земли Введение: Экологический рынок как игра с нулевой суммой Традиционная экология долгое время. . .
сукцессия 8. Как я спорил с ИИ, которые - агенты растений и ненавистники грибов!
anaschu 27.06.2026
Статья 1. Хроники грибного восстания: как Сократов диалог разрушил академические догмы ИИ Введение: Синдром «цифрового учебника» Современные большие языковые модели (LLM) обладают колоссальным. . .
Главный вопрос моделирования сукцессии
anaschu 27.06.2026
главный вопрос. Если эктомикориза лучше добывает недоступный фосфор. И ее масса максимальна из всех. А широколиственный лес тоже имеет самую крутую биомассу. То почему не возникло их симбиоза? Это. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru