【问题标题】:There is any way to do a partial specialization?有什么方法可以做部分专业化?
【发布时间】:2021-10-27 12:30:00
【问题描述】:

只是为了好玩,我正在尝试使用模板实现编译时 pow2 函数。 实际上,我可以这样做:

template <std::size_t n, typename type_t>
struct custom
{
    static type_t pow(type_t b) { return b * custom<n - 1, type_t>::pow(b); }
};

template <typename type_t>
struct custom<0, type_t>
{
    // (void)b; to avoid unused warning.
    static type_t pow(type_t b) { (void) b; return static_cast<type_t>(1); }
};

这样,它可以工作,但我的方法是更多地考虑这样的事情:

template <std::size_t n, typename type_t>
type_t cus_pow(type_t b) { return b * cus_pow<n - 1, type_t>(b); }

// This doesn't exists.
template <0, typename type_t>
type_t cus_pow(type_t b) { (void) b; return 1; }

因为如果我想创建任何部分元编程函数,不得不创建一个结构,它看起来太多了。

那么,有什么方法可以只用一个函数进行部分元编程?

【问题讨论】:

  • 你不能用函数模板做部分特化。
  • 如果你想要一个编译时间pow 计算,你可以使用带有for循环的constexpr函数。

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


【解决方案1】:

您不能部分专门化函数/方法。

您可以使用if constexpr (C++17) 来避免重复:

static type_t pow([[maybe_unused]]type_t b) {
    if constexpr (n == 0) {
        return static_cast<type_t>(1); }
    } else {
        return b * custom<n - 1, type_t>::pow(b);
    }
}

没有额外的运行时分支。

【讨论】:

    【解决方案2】:

    那么,有什么方法可以只用一个函数进行部分元编程?

    不:您不能对模板函数进行部分特化。

    但是还有其他方法可以解决这个问题。

    如果您可以使用 C++17,一个优雅的解决方案是使用 if constexpr(请参阅 Jarod42 的答案)。

    C++17之前,可以使用SFINAE

    template <std::size_t n, typename type_t>
    std::enable_if_t<n == 0u, type_t> cus_pow (type_t)
     { return 1; }
    
    template <std::size_t n, typename type_t>
    std::enable_if_t<n != 0u, type_t> cus_pow (type_t b)
     { return b * cus_pow<n - 1, type_t>(b); }
    

    根据n 的值启用/禁用零版本或非零版本(并定义(或至少声明)零版本之前,假设非零版本可以调用)。

    另一种解决方案是标签调度

    template <std::size_t, typename type_t>
    type_t cus_pow (std::true_type, type_t)
     { return 1; }
    
    template <std::size_t n, typename type_t>
    type_t cus_pow (std::false_type, type_t b)
     { return b * cus_pow<n-1u, type_t>(std::integral_constant<bool, n-1u==0u>{}, b); }
    
    template <std::size_t n, typename type_t>
    type_t cus_pow (type_t b)
     { return cus_pow<n>(std::integral_constant<bool, n==0u>{}, b); }
    

    使用“标签”(std::true_type 或 std::false_type)调用另一个函数,表明 n 是否为零。

    【讨论】:

    • 在较早的 C++ 版本中,您还可以使函数成为辅助类周围的瘦包装器,并且辅助类可以部分专门化。
    • @BenVoigt - 是的:是 OP 最初使用的解决方案(custom struct)。但仍然是一个类/结构,而不是函数,部分专业化。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-26
    • 2015-02-18
    • 2014-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多