Вопрос:

Наследование шаблона: символ не найден

c++ templates inheritance linker rcpp

103 просмотра

1 ответ

13619 Репутация автора

У меня проблемы с шаблонами и наследованием. Я записал какой-то проблемный код во что-то, что я могу опубликовать здесь. Мой код выглядит следующим образом:

///////////////////////////// My header.h file
#include <vector>

template <class T>
class Slider {
protected:
  std::vector<T> out;
public:
  Slider() : out() {}
  virtual void save_result();
};

template <class T>
class SlidingVar : public Slider<T> {
public:
  SlidingVar() {}
  void save_result() {}
};

template <class T>
void slide(std::vector<T> x, Slider<T> s) {}

///////////////////////////// My sliding_sd.cpp file
#include <vector>
#include "headers.h"

void sliding_var_window(std::vector<double> x) {
  SlidingVar<double> s;
  slide(x, s);
}

Хотя все вышеперечисленное является «чистым C ++» кодом, я делаю это в контексте Rпакета, для которого моя sliding_var_windowфункция будет экспортирована для вызова из R.

Все вышеперечисленное хорошо компилируется, но когда R загружает его, используя dlopen, я получаю Symbol not foundошибки об этой save_result()функции. Как ни странно, до того, как я это сократил, другие подобные функции работали просто отлично, но не эта. Вот последовательность сборки:

==> R CMD INSTALL --preclean --no-multiarch --with-keep.source tsevents

* installing to library ‘/Users/kwilliams/R/library/3.4’
* installing *source* package ‘TSEvents’ ...
** libs
clang++ -std=gnu++11 -I/usr/local/Cellar/r/3.4.2/lib/R/include -DNDEBUG  -I"/Users/kwilliams/R/library/3.4/Rcpp/include" -I/usr/local/opt/gettext/include -I/usr/local/opt/readline/include -I/usr/local/include   -fPIC  -g -O2 -c sliding_sd.cpp -o sliding_sd.o
clang++ -std=gnu++11 -dynamiclib -Wl,-headerpad_max_install_names -undefined dynamic_lookup -single_module -multiply_defined suppress -L/usr/local/opt/gettext/lib -L/usr/local/opt/readline/lib -L/usr/local/lib -L/usr/local/Cellar/r/3.4.2/lib/R/lib -L/usr/local/opt/gettext/lib -L/usr/local/opt/readline/lib -L/usr/local/lib -o TSEvents.so sliding_sd.o -L/usr/local/Cellar/r/3.4.2/lib/R/lib -lR -lintl -Wl,-framework -Wl,CoreFoundation
installing to /Users/kwilliams/R/library/3.4/TSEvents/libs
** R
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded
Error: package or namespace load failed for ‘TSEvents’ in dyn.load(file, DLLpath = DLLpath, ...):
 unable to load shared object '/Users/kwilliams/R/library/3.4/TSEvents/libs/TSEvents.so':
  dlopen(/Users/kwilliams/R/library/3.4/TSEvents/libs/TSEvents.so, 6): Symbol not found: __ZN6SliderIdE11save_resultEv
  Referenced from: /Users/kwilliams/R/library/3.4/TSEvents/libs/TSEvents.so
  Expected in: flat namespace
 in /Users/kwilliams/R/library/3.4/TSEvents/libs/TSEvents.so
Error: loading failed

Я подозреваю, что это на самом деле не имеет ничего общего с Rили Rcpp, но это обеспечивает мою среду сборки, поэтому, если кто-то может предложить способ продемонстрировать эту проблему в чистом наборе инструментов C ++, это было бы очень кстати.

Еще один лакомый кусочек, который я не понимаю - когда я смотрю на символы, определенные в объектном файле, у save_result()функции появляется unsigned shortтип возвращаемого значения, когда я объявил его следующим void:

% nm src/TSEvents.so | c++filt | grep result
0000000000002df0 unsigned short SlidingVar<double>::save_result()
                 U Slider<double>::save_result()

Это нормально?

Автор: Ken Williams Источник Размещён: 08.11.2017 10:52

Ответы (1)


1 плюс

36 Репутация автора

Решение

Я мог воспроизвести ошибку компоновщика после добавления int main() { }и компиляции g++без дополнительных опций:

sliding_sd.cpp:(.rdata$_ZTV6SliderIdE[__ZTV6SliderIdE]+0x8): undefined reference to `Slider<double>::save_result()'

Это означает, что в Slider<double>::save_result()виртуальной таблице (таблице виртуальных методов) есть ссылка на виртуальный метод, Slider<double>который не может быть разрешен во время компоновки. Причина в том , что вы объявили save_result()в template <class T> class Sliderно не определяют его (по крайней мере в коде вы выложили). Хотя Slider<double>::save_result()он никогда не используется в вашем примере, он должен быть определен (по крайней мере, при использовании обычного C ++, я не знаю о R), как он есть virtual. В противном случае vtable for Slider<double>не может быть создан во время связывания.

Когда изменено на

template <class T>
class Slider {
  /* ... */
  virtual void save_result() { }
};

ошибка компоновки исчезает (по крайней мере, в моем воспроизведении).

Автор: Fabian Размещён: 09.11.2017 12:46
Вопросы из категории :
32x32