【问题标题】:Storing templated derived classes in container在容器中存储模板派生类
【发布时间】:2017-04-07 16:56:37
【问题描述】:

我有一系列字段验证器,每个都类似于以下内容:

template <typename T>
class NameValidator : public Validator<T> {

    ...
    bool validate(const T& msg) const override { ... }
    ...

};

每个验证器都必须能够验证不同的消息类型,因此模板参数T

我想创建一个管理器类,作为这些验证器的公共网关。类似于以下内容:

class ValidatorManger {

    ...
    // Calls validate() functions for each field.
    template <typename T>
    bool validate(const T& msg) { ... }
    ...

};

因此,我需要将每个验证器类(例如:NameValidator&lt;T&gt;)存储在某种类型的数据结构中,然后在 ValidatorManager::validate() 中迭代它们。

有没有办法做到这一点,这样我就不必为每种消息类型明确专门化模板?我正在成像以下内容

validator_map.insert(std::make_pair("Name", NameValidator<T>));
validator_map.insert(std::make_pair("Age", AgeValidator<T>());
...

虽然这显然是胡言乱语。

问题:

  • 以前有没有人使用过这种模式并有解决方案来实现这一点?
  • 我是否应该重新考虑这个设计?

【问题讨论】:

  • 可以有一个元组并对其进行迭代。
  • 为什么特殊的验证器例如 NameValidator 是一个模板?它不应该派生自 Validator 还是它应该验证的任何类型?
  • @chris -- 你能澄清一下你的意思吗?
  • @ZivS -- 否。模板参数T 是消息的类型,而不是正在验证的底层事物的类型(通常,它不仅仅是一个简单的原语)。
  • @Ryan 重读这个问题,我希望您希望每个可能的T 都有一个vector&lt;Validator&lt;T&gt;&gt; 元组。元组存储每个向量,这是一个不同的类型。 validate 使用带有 std::get&lt;T&gt;(tuple) 的消息类型获取向量,并接收该消息类型的验证器向量,我希望它看起来像下面 max66 的答案。

标签: c++ templates generics design-patterns


【解决方案1】:

如果你想要一个容器,你可以按照这样的说明食用

validator_map.insert(std::pair("Name", NameValidator<T>()));
validator_map.insert(std::pair("Age", AgeValidator<T>()));

您需要知道您的类型 T,否则 NameValidator&lt;T&gt; 不是类型且 NameValidator&lt;T&gt;() 无法初始化对象。

所以我想你的validator_map 应该是ValidatorManager 中模板validator() 方法内的一个变量(静态?)。

所以,希望可以简化,我能想象到的最好的例子就是下面的例子

#include <set>
#include <vector>
#include <memory>
#include <iostream>

template <typename T>
struct Validator 
 { virtual bool validate (T const &) const = 0; };

template <typename T>
struct NameValidator : public Validator<T>
 {
   bool validate (T const & msg) const override
    { std::cout << "- name (" << msg << ")" << std::endl; return true; }
 };

template <typename T>
struct AgeValidator : public Validator<T>
 {
   bool validate (T const & msg) const override
    { std::cout << "- age  (" << msg << ")" << std::endl; return true; }
 };

struct ValidatorManager
 {
   template <typename T>
   bool validate (T const & msg) const
    {
      static bool first {true};
      static std::vector<std::unique_ptr<Validator<T>>> vvt;

      if ( first )
       {
         vvt.emplace_back( new NameValidator<T>{} );
         vvt.emplace_back( new AgeValidator<T>{} );

         first = false;
       }

      bool ret { true };

      for ( auto const & v : vvt )
         ret &= v->validate(msg);

      return ret;
    }
 };

int main()
 {
   ValidatorManager  vm;

   vm.validate(1);
   vm.validate(2.2);
   vm.validate("3.3");
 }

【讨论】:

    猜你喜欢
    • 2016-02-17
    • 2015-04-10
    • 1970-01-01
    • 2021-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-09
    相关资源
    最近更新 更多