【问题标题】:How to use Templated methods in C++?如何在 C++ 中使用模板化方法?
【发布时间】:2021-06-14 17:28:46
【问题描述】:

在我的头文件中,我有两种不同类型的对象 ImageFrame 和 `PointCloudFrame.然后用 std::variant 定义这些

struct ImageFrame{

};

struct PointCloudFrame{

};

using SensorFrame = std::variant<std::shared_ptr<ImageFrame>,
                                std::shared_ptr<PointCloudFrame>>;

我需要为这两个对象编写一个模板方法,所以我在头文件中这样做了:

template<class T>
std::string getFrameBin(const T& frame);

在cpp文件中

template <class ImageFrame>
std::string getFrameBin(const ImageFrame& image_frame)
{
  std::string x;
  return x;
}

template <class PointCloudFrame>
std::string getFrameBin(const PointCloudFrame& cloud_frame)
{
  std::string x;
  return x;
}

但是,我收到与以下相关的错误: error: redefinition of 'template&lt;class PointCloudFrame&gt; std::string

我做错了什么?有没有更优雅的方法来利用SensorFrame 对象

【问题讨论】:

  • 模板代码需要定义在头文件中,而不是cpp文件中。
  • std::variant 在 C++17 中添加。 C++11 标签没有意​​义。

标签: c++ c++11 templates


【解决方案1】:

这不需要是模板。它只是重载:

std::string getFrameBin(const ImageFrame&) {
    // do ImageFrame stuff
}

std::string getFrameBin(const PointCloudFrame&) {
    // do PointCloudFrame stuff
}

在头文件中声明这两个函数,并在.cpp文件中实现。

【讨论】:

    【解决方案2】:
    template <class ImageFrame>
    std::string getFrameBin(const ImageFrame& image_frame)
    {
      std::string x;
      return x;
    }
    

    意思是一样的

    template <class T>
    std::string getFrameBin(const T& image_frame)
    {
      std::string x;
      return x;
    }
    

    所以你定义了你的模板两次。如果您打算对模板化函数进行特化,则语法为:

    template <>
    std::string getFrameBin(const ImageFrame& image_frame)
    {
      std::string x;
      return x;
    }
    
    template <>
    std::string getFrameBin(const PointCloudFrame& cloud_frame)
    {
      std::string x;
      return x;
    }
    

    【讨论】:

    • 我将接受它作为最接近我想要的解决方案
    【解决方案3】:

    我会这样做:

    #include <cstdio>
    #include <memory>
    #include <variant>
    
    struct ImageFrame {};
    
    struct PointCloudFrame {};
    
    using SensorFrame =
        std::variant<std::shared_ptr<ImageFrame>, std::shared_ptr<PointCloudFrame>>;
    
    struct Visitor {
      void operator()(std::shared_ptr<ImageFrame> const&) const {
        // Use image frame
        std::puts("Visiting image");
      }
      void operator()(std::shared_ptr<PointCloudFrame> const&) const {
        // Use point cloud
        std::puts("Visiting point cloud");
      }
    };
    
    int main() {
      SensorFrame frame = std::make_shared<ImageFrame>();
      std::visit(Visitor{}, frame);
      frame = std::make_shared<PointCloudFrame>();
      std::visit(Visitor{}, frame);
    }
    

    【讨论】:

    • 这真是个好主意。
    • 我能知道Visitor{} 中的语法,尤其是这里的{} 是什么意思吗?
    • @raaj 它创建一个临时对象。你也可以使用Visitor()
    • 是使用该 operator() 标志的唯一选择吗?在那里有其他方法并让 std::visit 调用这些方法怎么样?
    • @raaj 不,它必须是operator()。这就是 API
    【解决方案4】:

    您定义了同一个模板两次。参数名称只是一个名称。将您的代码与:

    void foo(int x) {}
    
    void foo(int y) {}
    

    类似于你两次定义同一个模板,这是同一个函数的两个定义。

    当实现相同时,其实是模板的好例子,但只定义一次:

    template <class T>
    std::string getFrameBin(const T& cloud_frame)
    {
      std::string x;
      return x;
    }
    

    然后以任一类型作为参数调用它,模板参数将从函数参数中推导出来。当实现不相同时,您应该提供两个重载。如果您仍想继续使用该模板,您可以按照其他答案中的说明对其进行专门化。

    另请阅读:Why can templates only be implemented in the header file?

    【讨论】:

      猜你喜欢
      • 2013-03-07
      • 2022-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多