如何解决这种可变参数模板歧义

How to solve this variadic template ambiguity

提问人:Janilson 提问时间:6/18/2023 最后编辑:Janilson 更新时间:6/18/2023 访问量:51

问:

只要注释掉,以下代码就可以编译并正常运行。但是,一旦取消注释,编译就会失败,并出现错误“ 'value' is not a member of 'Arity<int (*)(int, int)>' ” 编译错误,我认为这是由于编译器选择了第一个模板而不是第二个模板。我尝试从第一个模板中删除括号,但问题仍然存在,只是这次出现了“不完整类型”编译错误。someFuncTemplate(func1)Arity<F>::value

使用时如何强制编译器选择正确的模板?Arity<F>

#include <iostream>

template <typename T>
struct Arity {};

template <typename Ret, typename... Args>
struct Arity<Ret(Args...)>
    : std::integral_constant<size_t, sizeof...(Args)> 
{};

int func1(int a, int b) { return a + b; }

template <typename F>
void someFuncTemplate(F)
{
    std::cout << Arity<F>::value;
}

int main()
{
    std::cout << Arity<decltype(func1)>::value << '\n';
    //someFuncTemplate(func1);
}
C++ 模板 元编程

评论


答:

4赞 Ted Lyngmo 6/18/2023 #1

您需要为第二种情况添加另一个专业化:

template <typename Ret, typename... Args>
struct Arity<Ret (*)(Args...)> : Arity<Ret(Args...)> {};
//               ^^^

您还可以添加

template <typename Ret, typename... Args>
struct Arity<Ret (&)(Args...)> : Arity<Ret(Args...)> {};

为了做出如下所示的函数声明:

template <typename F>
void someFuncTemplate(F&&) {
    std::cout << Arity<F>::value;
}

演示

评论

0赞 Janilson 6/18/2023
嗯,这比我想象的要简单。Ret(Args...) 和 Ret(*)(Args...) 有什么区别?
0赞 Ted Lyngmo 6/18/2023
@Janilson 当您将函数作为参数传递给函数而不是像在 中那样对它执行操作时,它就是这种类型。 与FdecltypemainsomeFuncTemplate(func1);someFuncTemplate(&func1);
2赞 Jerry Coffin 6/18/2023 #2

作为为指向函数的指针添加专用化的替代方法,您可以修改为通过引用获取其参数:someFunctTemplate

// preceding unchanged

template <typename F>
void someFuncTemplate(F const &)
//......................^^^^^^^
{
    std::cout << Arity<F>::value;
}

int main()
{
    someFuncTemplate(func1);
}