【问题标题】:C++ variadic template deduction failC++ 可变参数模板推导失败
【发布时间】:2020-11-24 11:00:31
【问题描述】:

我写了一个带有递归计算的可变参数模板函数。对于最后一个参数,我实现了一个没有可变参数包的专业化,一切正常。

现在我想将可变参数函数参数转换为模板参数。

这是我的尝试:

template<typename N, int p> // specialization
N constexpr myadd(const N &n)
{
    return n + p;
}

template<typename N, int p, int ... v> // variadic
N constexpr myadd(const N &n)
{
    return myadd<N, v...>(n) + p;
}

int testfun()
{
    return myadd<int, 2>(7);
}

gcc 和 clang 报告了一个模棱两可的重载,并且无法在 'specialization' 和 'variadic' 使用空参数包之间做出决定。

我尝试删除特化并检查可变参数模板中的包大小,但没有特化编译器无法推断出参数“p”。 p>

【问题讨论】:

  • 请注意,没有特化,只是不同的重载。

标签: c++ templates


【解决方案1】:

正如this answer 中所述,可变参数包确实可以是空的。 但是您可以使用SFINAE 专门处理非空可变参数包的情况。

例如:

#include <iostream>
#include <type_traits>

template<typename N, int p> // specialization
N constexpr myadd(const N &n)
{
    std::cout << "specialization" << std::endl;
    return n + p;
}

template<typename N, int p, int ... v, class = std::enable_if_t<(sizeof...(v) > 0)>> // variadic
N constexpr myadd(const N &n)
{
    std::cout << "variadic" << std::endl;
    return myadd<N, v...>(n) + p;
}

int main()
{
    std::cout <<  myadd<int, 2>(7) << std::endl;
    std::cout <<  myadd<int, 2, 4>(7) << std::endl;
    
    return 0;
}

Live on Coliru

【讨论】:

  • template&lt;typename N, int p1, int p2, int ... v&gt; N constexpr myadd(const N&amp;); 没有 SFINAE。
【解决方案2】:

参数包确实可以为空。您可以通过更改专业化来处理不添加任何内容的情况来避免歧义:

template<typename N> // specialization
N constexpr myadd(const N &n)
{
    return n;
}

template<typename N, N p, N ... v> // variadic
N constexpr myadd(const N &n)
{
    return myadd<N, v...>(n) + p;
}

使用 C++17,您可以使用 fold expressions 来简化此操作:

template<typename N, N ... v> // variadic
N constexpr myadd(const N &n)
{
    return (v + ... + n);
}

【讨论】:

  • 很好的建议,但对于真正的算法,没有简单的方法可以更改它以适合您的代码。我选择了@francesco 的解决方案。
  • 你的真实算法有什么不同?
  • 你可以在这里找到我原来的算法:pastebin.com/7cUnGfnJ。我想只用给定的因子计算“n”以上的最小整数(以确定理想的 FFT 大小)。
  • 但是该算法将值作为函数参数而不是模板参数传递,并且可以正常编译。我可以看到折叠表达式在那里不合适。
  • @g-sliepen:这正是我的意思。参数是内联的。将其与template with function parameters 进行比较。我正在使用除法,因此如果编译器考虑固定值,这是一个巨大的优势。
猜你喜欢
  • 2012-10-26
  • 2020-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-28
  • 2014-09-22
  • 2011-07-28
相关资源
最近更新 更多