提问人:ITiger 提问时间:1/18/2018 最后编辑:ITiger 更新时间:1/18/2018 访问量:674
VisualC++ Tensorflow C API Wrapper 导致LNK2019
VisualC++ Tensorflow C API Wrapper causes LNK2019
问:
我目前正在编写一个 VisualC++ 12 Tensorflow 包装器,以便为 Tensorflow 对象检测 API 启用推理任务。但是,我遇到了一些类型LNK2019的链接错误(“未解析的外部符号”)。
我研究了此错误的一些常见原因,并发现了以下内容,但我无法在我的代码中发现其中任何一个(原因列在链接器工具错误LNK2019的Microsoft参考中)。
下面是导致错误的代码片段:
文件 TensorflowTensor.h:
namespace tf { class TensorflowTensor : public TensorflowCWrapper<TF_Tensor> { public: TensorflowTensor(const cv::Mat& input_image); TensorflowTensor(TF_Tensor* tensor); // inner class for convenient access to tensors' data template<typename DType, size_t D> class TensorView { public: TensorView<DType, D>(TensorflowTensor& tensor); const DType& operator()(std::array<size_t, D> n) const; DType& operator()(std::array<size_t, D> n); size_t NumElements() const; private: DType* data_; std::array<size_t, D> dims_; size_t num_el_; }; template<typename DType, size_t D> TensorView<DType, D> View(); }; }
TensorflowTensor.cpp 中的实现(仅导致链接器错误的行):
namespace tf { // Constructors of TensorflowTensor are here template<typename DType, size_t D> TensorflowTensor::TensorView<DType, D>::TensorView(TensorflowTensor& tensor) { if (tensor.NumDims() != D) { throw std::runtime_error("Number of dimensions do not match!"); } num_el_ = 1; for (size_t i = 0; i < D; ++i) { dims_[i] = tensor.Dim(i); num_el_ *= dims_[i]; } if (tensor.NumBytes() != (num_el_ * sizeof(DType))) { throw std::runtime_error("Wrong TensorView!"); } data_ = static_cast<DType*>(tensor.Bytes()); } template<typename DType, size_t D> const DType& TensorflowTensor::TensorView<DType, D>::operator()(std::array<size_t, D> n) const { return data_[ComputeOffset(n)]; } template<typename DType, size_t D> DType& TensorflowTensor::TensorView<DType, D>::operator()(std::array<size_t, D> n) { return data_[ComputeOffset(n)]; } template<typename DType, size_t D> size_t TensorflowTensor::TensorView<DType, D>::NumElements() const { return num_el_; } template<typename DType, size_t D> TensorflowTensor::TensorView<DType, D> TensorflowTensor::View() { return TensorView<DType, D>(*this); } }
以下是我从中调用函数的行(在方法中: ):
TensorflowInference::detect(* some args */)
const auto output_scores = result_tensors[0]->TensorflowTensor::View<float, 2>(); const auto output_boxes = result_tensors[1]->TensorflowTensor::View<float, 3>(); const auto output_classes = result_tensors[2]->TensorflowTensor::View<float, 2>(); // copy detections to the results vector results.clear(); for (size_t i = 0; i < output_scores.NumElements(); ++i) { if (output_scores({{0, i}}) > 0.) { results.emplace_back(output_classes({{ 0, i }}), output_scores({{ 0, i }}), output_boxes({{ 0, i, 1 }}), output_boxes({{ 0, i, 0 }}), output_boxes({{ 0, i, 3 }}), output_boxes({{ 0, i, 2 }})); } }
如果我注释这些行,我不会收到错误。
我已经包含了所有头文件,除了以下 5 个 LNK2019 之外,没有收到任何编译器错误或警告:
TensorflowInference.obj:错误 LNK2019:未解析的外部符号“public: class tf::TensorflowTensor::TensorView __cdecl tf::TensorflowTensor::View(void)” (??$View@M$01@TensorflowTensor@tf@@QEAA?AV?$TensorView@M$01@01@XZ) 在函数 “public: void __cdecl tf::TensorflowInference::d etect(class cv::Mat const &,class std::vector > &)const ” (?detect@TensorflowInference@tf@@QEBAXAEBVMat@cv@@AEAV?$vector@UDetection@tf@@V?$allocator@UDetection@tf@@@std@@@std@@@Z)
TensorflowInference.obj:错误 LNK2019:未解析的外部符号“public: float const & __cdecl tf::TensorflowTensor::TensorView::operator()(class std::array)const ” (??R?$TensorView@M$01@TensorflowTensor@tf@@QEBAAEBMV?$array@_K$01@std@@@Z) 在函数“public: void __cdecl tf::TensorflowInference::d etect(class cv::Mat const &,class std::vector > &)const ” (?detect@TensorflowInference@tf@@QEBAXAEBVMat@cv@@AEAV?$vector@UDetection@tf@@V?$allocator@UDetection@tf@@@std@@@std@@@Z)
TensorflowInference.obj:错误 LNK2019:未解析的外部符号“public:unsigned __int64 __cdecl tf::TensorflowTensor::TensorView::NumElements(void)const ”(?01@TensorflowTensor@tf@@QEBA_KXZ$TensorView NumElements@函数“public: void __cdecl tf::TensorflowInference::d etect(class cv::Mat const &,class std::vector > &)const ” (?detect@TensorflowInference@tf@@QEBAXAEBVMat@cv@@AEAV?$vector@UDetection@tf@@V?$allocator@UDetection@tf@@@std@@@std@@@Z) 中引用
TensorflowInference.obj:错误 LNK2019:未解析的外部符号“public: class tf::TensorflowTensor::TensorView __cdecl tf::TensorflowTensor::View(void)” (??$View@M$02@TensorflowTensor@tf@@QEAA?AV?$TensorView@M$02@01@XZ) 在函数“public: void __cdecl tf::TensorflowInference::d etect(class cv::Mat const &,class std::vector > &)const ” (?detect@TensorflowInference@tf@@QEBAXAEBVMat@cv@@AEAV?$vector@UDetection@tf@@V?$allocator@UDetection@tf@@@std@@@std@@@Z)
TensorflowInference.obj:错误 LNK2019:未解析的外部符号“public: float const & __cdecl tf::TensorflowTensor::TensorView::operator()(class std::array)const ” (??R?$TensorView@M$02@TensorflowTensor@tf@@QEBAAEBMV?$array@_K$02@std@@@Z) 在函数“public: void __cdecl tf::TensorflowInference::d etect(class cv::Mat const &,class std::vector > &)const ” (?detect@TensorflowInference@tf@@QEBAXAEBVMat@cv@@AEAV?$vector@UDetection@tf@@V?$allocator@UDetection@tf@@@std@@@std@@@Z)
主啊,这是一堵文字墙,但我只包括了错误的重要行。
我很感激任何帮助我解决这些错误的提示!我对 C++ 编程还很陌生,尤其是模板仍然让我有些痛苦。
答:
C++ 编译器由两个主要阶段组成:
- 编译:这是将*.cpp文件转换为*.obj文件的地方。在此阶段之后会出现编译时错误。
如果未发生编译时错误,则生成过程将移至:
- 链接:这是将所有 obj 文件与任何依赖项(如 lib/dll 文件)链接在一起以创建最终可执行文件。如果缺少任何依赖项,则会出现链接时间错误。
因此,考虑到这些信息,让我们看一下您的错误: “LNK2019”。这意味着这是一个链接时间错误(用 LNK 表示),错误号表示未解析的符号,并且在几个地方提到了 TensorFlowTensor,它表示您刚刚发布的文件。
因此,发生的情况是链接器找不到每个错误中指定的函数的定义。在这种非常具体的情况下,这样做的原因是您已在 cpp 文件中提供了模板化函数的实现。
这将导致问题,因为模板函数必须以内联方式定义,即在头文件中。
将所有代码移入 ,如下所示:TensorflowTensor.cpp
TensorflowTensor.h
namespace tf {
class TensorflowTensor : public TensorflowCWrapper<TF_Tensor>
{
public:
TensorflowTensor(const cv::Mat& input_image);
TensorflowTensor(TF_Tensor* tensor);
// inner class for convenient access to tensors' data
template<typename DType, size_t D>
class TensorView
{
public:
TensorView<DType, D>(TensorflowTensor& tensor){
// Constructor body goes here instead of cpp file.
}
const DType& operator()(std::array<size_t, D> n) const{
// operator body goes here
}
DType& operator()(std::array<size_t, D> n){
// Here too
}
size_t NumElements() const;
private:
DType* data_;
std::array<size_t, D> dims_;
size_t num_el_;
};
template<typename DType, size_t D>
TensorView<DType, D> View();
};
}
这样,编译器和链接器就可以找到要使用的函数的定义。
评论