【问题标题】:c++ template class print functionc++模板类打印函数
【发布时间】:2017-11-28 08:21:14
【问题描述】:

我正在尝试为我的模板类编写一个打印函数:

struct ColumnKey;

template <class Type, class Key = ColumnKey>
class Column {
protected:
  std::shared_ptr<Type> doGet() {
    std::lock_guard<std::mutex> lock(mutex_);
    return std::make_shared<Type>(value_);
  }
  void doSet(const std::shared_ptr<Type> &value) {
    std::lock_guard<std::mutex> lock(mutex_);
    value_ = *value;
  }
private:
  Type value_;
  std::mutex mutex_;
};

template<class... Columns>
class Table : private Columns... {
public:
  template<class Type, class Key = ColumnKey>
  std::shared_ptr<Type> get() {
    return Column<Type, Key>::doGet();
  }

  template<class Type, class Key = ColumnKey>
  void set(const std::shared_ptr<Type> &value) {
    Column<Type, Key>::doSet(value);
  }

  std::string get_table_row() {
    return "hello_row";
  }
};

我想在Table 类中创建一个函数get_table_row,它返回columnA + "," + columnB + "," + ..

我正在尝试以这种方式编写,但出现编译错误。有人可以指出我的方法中的错误吗?

    template <class Column<class Type, class Key = ColumnKey>>
    std::string get_row() {
        return std::to_string( *Column<Type, Key>::doGet() );
    }

    template <class Column<class Type, class Key = ColumnKey>, class... Columns>
    std::string get_row() {
        return ( std::to_string(*Column<Type, Key>::doGet()) + "," + Columns.get_row() );
    }

我正在努力做到这一点,有人可以指导我吗?

【问题讨论】:

  • 您可能希望递归地遍历模板参数,请参阅this answer
  • @piwi 我认为这与我想要实现的目标有些不同。我也有Key,我想return 一个值。另外,我只想打电话给Table&lt;Column&lt;int&gt;, Column&lt;std::string, Key1&gt;, Column&lt;std::string, Key2&gt;&gt;.get_row()。基本上,没有传递任何参数。
  • @piwi 可能是链接的,但我很困惑,任何帮助将不胜感激
  • 您对shared_ptr 的使用对我来说似乎很复杂。你想在那里做什么?在当前的实现中,每次调用doGet 最终都会将列内容复制到新分配的shared_ptr

标签: c++ variadic-templates template-meta-programming


【解决方案1】:

你应该使用fold expressions

template<typename T, typename K>
struct Column
{
    T val;
};

template<typename FirstColumn, typename... Columns>
struct Table : private FirstColumn, private Columns...
{
    std::string get_table_row()
    {
        using std::to_string;
        return (to_string(FirstColumn::val) + ... + ("," + to_string(Columns::val)));
    }
};

如果您有一个用例,您可以专门针对零列的情况。

【讨论】:

  • 感谢您的准确回答。然后必须在 MacOS 上使用 -std=c++1z 编译
【解决方案2】:

这是一个可行的解决方案。

结构体printer 遍历可变参数模板并为每种类型调用 Table::get:

template <typename TableT>
struct printer
{
  printer(TableT& t): m_table(t) {}

  template <typename T>
  void impl(std::ostream& output)
  {
    using type = typename column_type<T>::type;
    output << *m_table.template get<type>();
  }

  template <typename First, typename Second, typename... Other>
  void impl(std::ostream& output)
  {
    impl<First>(output);
    impl<Second, Other...>(output);
  }

  template <typename... T>
  std::string invoke()
  {
    std::ostringstream out;
    impl<T...>(out);
    return out.str();
  }

  TableT& m_table;
};

我写了一个trait来推导出列Type

template <typename> struct column_type;
template <template <typename, typename> class Column, typename Type, typename Key>
struct column_type<Column<Type, Key>>
{
    using type = Type;
};

为了使用打印机,我将 Columns 类型保存在一个元组中并解压它:

template <typename... Columns>
class Table: private Columns...
{
  using columns_t = std::tuple<Columns...>;
public:
    std::string get_table_row() {
    return unpack<columns_t>::invoke(*this);
  }
};

结构体 unpack 调用打印机:

template <typename> struct unpack;
template <typename... T> struct unpack<std::tuple<T...>>
{
  template <typename TableT>
  static std::string invoke(TableT& t)
  {
    printer<TableT> p(t);
    return p.invoke<T...>();
  }
};

【讨论】:

    【解决方案3】:

    您的get_row 成员函数确实格式不正确。我们将需要递归处理这些列。为此,我们需要一个辅助类(因为函数模板不能部分特化),以及一个辅助类型特征来推断您的ColumnKeyType 参数:

    template <typename>
    struct column_traits;
    
    template <typename Type, typename Key>
    struct column_traits<Column<Type, Key>> {
        using type = Type;
        using key = Key;
    };
    
    template <typename...>
    struct TableRowPrinter;
    
    template <typename Col>
    struct TableRowPrinter<Col> {
        template <typename TableT>
        static std::string get_row(TableT& table) {
            using col_traits = column_traits<Col>;
            return std::to_string(
                   *table.template get<typename col_traits::type,
                                       typename col_traits::key>());
        }
    };
    
    template <typename HeadCol, typename... Cols>
    struct TableRowPrinter<HeadCol, Cols...> {
        template <typename TableT>
        static std::string get_row(TableT& table) {
            using col_traits = column_traits<HeadCol>;
            return std::to_string(
                       *table.template get<typename col_traits::type,
                                           typename col_traits::key>()) +
                   ", " + TableRowPrinter<Cols...>::get_row(table);
        }
    };
    

    现在,在Table 类模板中,您需要做的就是添加适当的成员函数:

    std::string get_row() {
        return TableRowPrinter<Columns...>::get_row(*this);
    }
    

    您可以在 Coliru 上查看一个工作示例。

    注意:我没有“清理”不寻常的 shared_ptr 用法……那是另一个话题……

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-08
      • 2017-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多