【问题标题】:What is the easiest way to make template function code depending on the parameter type根据参数类型制作模板功能代码的最简单方法是什么
【发布时间】:2012-02-07 16:28:54
【问题描述】:

我想编写一个模板函数来检查一些 Timestamp 属性(类继承自 Timed),但也必须适用于没有时间戳的类型。我发现的最好(但仍然很丑)的解决方案如下:

class Timed {
  protected:
    int mTime;        
  public:
    explicit Timed(int time=0): mTime(time){}
    int getT() const {return mTime;}

};

template<typename T>
bool checkStale(T const* ptr) const {
  return checkStaleImp(ptr, boost::is_base_of<Timed, T>() );
}

template<typename T>
template<bool b>
bool checkStaleImp(T const* ptr, boost::integral_constant<bool, b> const &){
  return true;
}

template<typename T>
bool checkStaleImp(T const* ptr, boost::true_type const&){
  const int oldest = 42;
  return (42 <= ptr->getT());  
}

这是一个功能的三个功能。有没有更简单的方法来实现这一点,例如使用boost::is_base_of 或某事。在 if 条件或 boost::enable if 中类似,将函数输出转换为非源自Timed 的类的一种常量。遗憾的是,具有虚拟功能的解决方案不是一种选择。

【问题讨论】:

  • @AJG85:实际函数是类模板的成员(省略以缩短示例)所以模板与否的问题已经过时,但阅读 fernandes 的答案我认为一个更简单的解决方案是可能
  • 这就是评论的重点。让您考虑诸如重载等替代方案。

标签: c++ templates boost sfinae


【解决方案1】:

你可以用两个简单的重载而不用模板机制来做同样的事情:

bool checkStale(void const* ptr){
  return true;
}

bool checkStale(Timed const* ptr){
  const int oldest = 42;
  return (oldest <= ptr->getT());  
}

无需在is_base_of 上分派标签。

【讨论】:

  • +1 为简单起见。他还可以对Timed 的模板函数进行一个完整的特化,以达到类似的效果。
  • 我认为这行不通。 Timed的派生类会实例化函数模板,而不是调用带参数Timed const*的重载。
  • @Nawaz 好点。我应该把所有的模板都拿出来 :S
  • 现在就编译器而言这看起来是正确的。 +1。但是如果第一个函数的实现取决于类型呢?在我的回答中,我认为return true 是为了减少问题的冗长,它的实际实现取决于 T。
  • @Nawaz:是的,这需要一个实际的模板。但我相信情况并非如此,因为 OP 说他想“将函数输出转换为不是从 Timed 派生的类的一种常量”
【解决方案2】:

我不认为这是相当丑的解决方案,正如你所说。但是,如果将辅助函数实现为本地类的静态成员,则可以缩小辅助函数的范围:

template<typename T>
bool checkStale(T const* ptr) const 
{
  struct local
  {
      static bool checkStaleImp(T const* ptr, boost::false_type const &)
      {
         return true;
      }
      static bool checkStaleImp(T const* ptr, boost::true_type const&)
      {
        const int oldest = 42;
        return (42 <= ptr->getT());  
      }
  };
  return local::checkStaleImp(ptr, boost::is_base_of<Timed, T>());
}

现在,向用户公开了一个函数,以及本地类中的实际实现。

顺便说一句,在 C++11 中,您可以使用 std::is_base_of 代替 boost 的版本。与std::true_typestd::false_type 相同。

【讨论】:

  • 感谢您在我的回答中指出这个问题,而不是支持它。有一个 +1。
  • 有趣的方法,更整洁。如果我没记错的话,你的代码会漏掉一个静态的。对我来说,曝光不是问题,因为所有三个函数都是私有类成员(为简单起见,省略了),但仍然很有趣
【解决方案3】:

使用enable_if 在可能的重载之间进行选择。由于以下示例中使用的条件是互补的,因此总会有一个可用的重载,因此没有歧义

template<typename T>
typename std::enable_if<std::is_base_of<Timed,T>::value,bool>::type
checkStale(T const *ptr) const {
    const int oldest = 42;
    return oldest <= ptr->getT();
}

template<typename T>
typename std::enable_if<!std::is_base_of<Timed,T>::value,bool>::type
checkStale(T const *ptr) const {
    return true;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-28
    • 1970-01-01
    • 2012-08-12
    • 1970-01-01
    • 1970-01-01
    • 2011-10-06
    • 1970-01-01
    相关资源
    最近更新 更多