为什么这个可变函数模糊不清?

时间:2011-08-18 14:50:39

标签: c++ variadic-templates c++11

这与my earlier post有关。我想知道为什么一个尝试的解决方案不起作用。

template <typename... T>             /* A */
size_t num_args ();

template <>
size_t num_args <> ()
{
    return 0;
}

template <typename H, typename... T> /* B */
size_t num_args ()
{
    return 1 + num_args <T...> ();
}

如果我尝试拨打电话,比如num_args<int,float>(),那么错误就是函数调用不明确:

  • A,T = {int,float}
  • B,H = int,T = {float}

我不明白这是多么模糊 - A是声明,B是A声明的函数的定义。对吗?

我正在努力让this example工作,对我之前的问题的回答似乎声称它永远不会工作。

如果是这种情况,那么可变函数的重点是什么? 可以他们做什么?

3 个答案:

答案 0 :(得分:7)

  

我不明白这是多么模棱两可 - A是声明而B   是由A声明的函数的定义吗?对吗?

没有。 A是函数模板的声明,B是另一个函数模板的声明(和定义)。

编译器无法在两者之间做出决定:它们都没有参数,模板参数与两者都匹配。

中间的一个是A中声明的函数模板的显式完全特化。

如果你试图使B成为A:

的另一种专业化
template <typename H, typename... T> /* B */
size_t num_args<H, T...>()
{
    return 1 + num_args <T...> ();
}

...你最终会得到一个功能模板的部分特化,这是不允许的。

你可以通过使用带有部分特化的类模板和调用类模板的函数模板的常用技巧来实现这一点:

template <typename... T>
class Num_Args;

template <>
struct Num_Args <>
{
    static constexpr size_t calculate() {
        return 0;
    }
};

template <typename H, typename... T>
struct Num_Args <H, T...>
{
    static constexpr size_t calculate() {
        return 1 + Num_Args<T...>::calculate();
    }
};

template <typename... T> /* B */
constexpr size_t num_args ()
{
    return Num_Args<T...>::calculate();
}

答案 1 :(得分:3)

适用于自由可变参数函数模板的有用性/无用性:这些通常的用例是具有可变参数函数参数列表,在这种情况下,空案例的常规重载可以正常运行:

size_t num_args()
{
    return 0;
}

template <typename H, typename... T> /* B */
size_t num_args (H h, T... t)
{
    return 1 + num_args(t...);
}

<小时/>

编辑:

据我所知,以下滥用enable_if应该可以解决您原来的问题:

#include <utility>

// Only select this overload in the empty case 
template <typename... T>
typename std::enable_if<(sizeof...(T) == 0), size_t>::type
num_args() 
{ 
    return 0;
}

template <typename H, typename... T>
size_t
num_args() 
{
    return 1 + num_args<T...>();
}

(Edit2:反转重载的顺序以使代码实际编译)

答案 2 :(得分:-1)

这里的问题是也会捕获空列表,所以由于你有一个空的重载作为递归锚点,它会看到两者并且不知道选择哪个。