当前位置: 首页 > 知识库问答 >
问题:

递归可变模板函数-没有歧义?

傅增
2023-03-14

我目前正在研究可变参数模板,作为消化我一直在阅读的一些内容的一个小练习,我编写了一个小函数来输出其所有参数类型的名称:

#include "stdafx.h"
#include <iostream>
#include <string>

template<typename Next, typename... Rest>
std::string get_arg_types(Next next, Rest... rest)
{
    return std::string(typeid(Next).name()) + "\n" + get_arg_types(rest...);
}

template<typename Last>
std::string get_arg_types(Last last)
{
    return std::string(typeid(Last).name());
}

int main()
{
    float f = 0;
    double d = 0;
    int i = 0;

    std::cout << get_arg_types(f, d, i);

    return 0;
}

令我惊讶的是,这是使用VC 12.0编译的,并且(似乎)工作得很好。

当只剩下一个参数时,由于重载之间的不确定性,我预计会出现错误,因为我了解到模板参数包可以为空/包含0个参数。

所以我的问题是为什么这行得通?“潜在的歧义”是如何解决的?两个函数的签名不是都只有一个参数吗?我觉得我可能在某个地方遗漏了一些重要的概念,因为在我的脑海里上面的例子不应该编译,但显然我错了。

亲切问候:)

共有1个答案

爱炯
2023-03-14

您的代码有问题,但原因不同。正如在对相关问题的回答中所指出的,递归调用可变模板函数重载时的模糊调用,代码中的第二个重载被认为更专业。但是,它应该出现在带有参数包的例程之前。使用gcc8.2.1或clang6.0.1编译代码时会出现如下错误:

variadic.cpp: In instantiation of ‘std::__cxx11::string get_arg_types(Next, Rest ...) [with Next = int; Rest = {}; std::__cxx11::string = std::__cxx11::basic_string<char>]’:
variadic.cpp:7:67:   recursively required from ‘std::__cxx11::string get_arg_types(Next, Rest ...) [with Next = double; Rest = {int}; std::__cxx11::string = std::__cxx11::basic_string<char>]’
variadic.cpp:7:67:   required from ‘std::__cxx11::string get_arg_types(Next, Rest ...) [with Next = float; Rest = {double, int}; std::__cxx11::string = std::__cxx11::basic_string<char>]’
variadic.cpp:23:39:   required from here
variadic.cpp:7:67: error: no matching function for call to ‘get_arg_types()’
     return std::string(typeid(Next).name()) + "\n" + get_arg_types(rest...);
error: no matching function for call to ‘get_arg_types()

从错误中可以看出,即使<code>get_。一个简单的解决方案是将带有单个参数的<code>get_。

或者,您可以消除get_arg_types的专用化单参数,并添加具有 0 个参数的专用化:

std::string get_arg_types()
{
  return std::string();
}

同样,这种专门化应该放在(或至少声明)模板例程之前。请注意,使用第二种解决方案,输出略有变化。

 类似资料:
  • 我试图编写一个可变函数模板来计算的字节大小。这将用于一个网络编程项目,我正在工作。第一步,我在没有工作的variadic模板的情况下想出了这个: 错误代码#2。如果我将variadic模板放在不同的位置: 我得到了 错误:重载的'size t ()'调用不明确

  • 以这种方式传递参数有问题,我得到以下错误:“std::thread::thread”:没有重载函数接受4个参数。我怎么能这么做?

  • 在C++11之前,类模板和函数模板只能含有固定数量的模板参数。C++11增强了模板功能,允许模板定义中包含0到任意个模板参数,这就是可变参数模板。可变参数模板的加入使得C++11的功能变得更加强大,而由此也带来了许多神奇的用法。 可变参数模板 可变参数模板和普通模板的语义是一样的,只是写法上稍有区别,声明可变参数模板时需要在typename或class后面带上省略号...: template<ty

  • 我试图理解下面代码中的编译器错误。我有一个variadic模板函数,它接受具有指定类型的lambda,试图调用该函数会导致模板由于不匹配而不被视为有效的候选模板。 如果我将声明更改为不变: 然后它为上面的玩具示例工作,但对于真正的问题,我需要任意的论点。我是不是缺少了什么,或者还有什么方法可以做到这一点? 编辑:这被错误地标记为重复,我相信--受骗者没有回答我所问的问题。这个问题特别与这里的var

  • 问题 你想在一个函数中调用相同的函数。 解决方案 使用一个命名函数: ping = -> console.log "Pinged" setTimeout ping, 1000 若为未命名函数,则使用 @arguments.callee@: delay = 1000 setTimeout((-> console.log "Pinged" setTimeout arg

  • 在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。 举个例子,我们来计算阶乘n! = 1 x 2 x 3 x ... x n,用函数fact(n)表示,可以看出: fact(n) = n! = 1 x 2 x 3 x ... x (n-1) x n = (n-1)! x n = fact(n-1) x n 所以,fact(n)可以表示为n x fact(n-1),