【问题标题】:Template specialization fails because of unknown template definition由于未知的模板定义,模板特化失败
【发布时间】:2016-01-06 22:49:06
【问题描述】:

我的模板专业化不起作用。有谁知道我如何使用模板正确实现此功能?

template<class T>
float hz_to_nsec(const T &freq) {
    return freq != 0 ? static_cast<float>(NSEC_PER_SEC) / freq : 0;
}

template <>
double hz_to_nsec<double>(const double &freq) {
    return freq != 0 ? static_cast<double>(NSEC_PER_SEC) / freq : 0;
}

【问题讨论】:

标签: c++ c++11


【解决方案1】:

返回类型和主模板必须匹配:

template<class T>
float hz_to_nsec(const T &freq) {
    return freq != 0 ? static_cast<float>(NSEC_PER_SEC) / freq : 0;
}

template <>
float hz_to_nsec<double>(const double &freq) {
^^^^^
    return freq != 0 ? static_cast<float>(NSEC_PER_SEC) / freq : 0;
                                   ^^^^^
}

或者,您可以提供重载而不是模板特化:

template<class T>
float hz_to_nsec(const T &freq) {
    return freq != 0 ? static_cast<float>(NSEC_PER_SEC) / freq : 0;
}

double hz_to_nsec(const double &freq) {
    return freq != 0 ? static_cast<double>(NSEC_PER_SEC) / freq : 0;
}

【讨论】:

  • 虽然这可能会消除编译器错误,但现在专业化已经毫无用处了。
  • @5gon12eder 为什么会这样?
  • @5gon12eder 如果您希望特化具有不同的返回类型,您可以为返回类型编写一个特征并特化该特征。
  • 如果您只是删除专业化,您会得到任何不同的行为吗? (谈论你的第一个例子。)我认为这个想法是为了避免将doubles 缩小到float
【解决方案2】:

answer by @101010 解决了您的模板错误。但是,您不需要将第二个函数作为模板特化。它可能只是一个过载。

// template <>
// No need to use template specialization.
// Just use an overload.
double hz_to_nsec(double freq) {
    return freq != 0 ? static_cast<double>(NSEC_PER_SEC) / freq : 0;
}

【讨论】:

    【解决方案3】:

    返回类型必须匹配。但是,它也可以被模板化:

    template<class T>
    T hz_to_nsec(const T &freq) {
        return freq != 0 ? static_cast<float>(NSEC_PER_SEC) / freq : 0;
    }
    
    template <>
    double hz_to_nsec<double>(const double &freq) {
        return freq != 0 ? static_cast<double>(NSEC_PER_SEC) / freq : 0;
    }
    

    或者你可以使用一个特征:

    template<class T>
    struct RetT
    {
        using Type = float;
    };
    
    template <>
    struct RetT<double>
    {
        using Type = double;
    };
    
    template<class T>
    typename RetT<T>::Type hz_to_nsec(const T &freq) {
        return freq != 0 ? static_cast<float>(NSEC_PER_SEC) / freq : 0;
    }
    
    template <>
    double hz_to_nsec<double>(const double &freq) {
        return freq != 0 ? static_cast<double>(NSEC_PER_SEC) / freq : 0;
    }
    

    或者你甚至不需要模板特化,你可以重载函数:

    template<class T>
    float hz_to_nsec(const T &freq) {
        return freq != 0 ? static_cast<float>(NSEC_PER_SEC) / freq : 0;
    }
    
    double hz_to_nsec(const double &freq) {
        return freq != 0 ? static_cast<double>(NSEC_PER_SEC) / freq : 0;
    }
    

    【讨论】:

      【解决方案4】:

      我认为专业化在这里是错误的工具。相反,请考虑将目标类型作为附加类型参数。

      // C++14
      
      template <typename OutputT, typename InputT>
      std::enable_if_t
      <
        std::is_arithmetic<InputT>::value && std::is_floating_point<OutputT>::value,
        OutputT
      >
      hz_to_nsec(const InputT freq)
      {
        return (freq != InputT {0})
          ? static_cast<OutputT>(NSEC_PER_SEC) / static_cast<OutputT>(freq)
          : OutputT {0};
      }
      

      我将OutputT 放在第一位,因为它无法推断。我还将InputTOutputT 的允许类型限制为可能是合理的类型。

      可以这样使用。

      hz_to_nsec<double>(10);    // InputT = int,           OutputT = double
      hz_to_nsec<float>(10.0f):  // InputT = float,         OutputT = float
      hz_to_nsec<float>(5UL);    // InputT = unsigned long, OutputT = float
      

      【讨论】:

        猜你喜欢
        • 2012-02-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多