【问题标题】:Recursive Variadic Template Function - No ambiguity?递归可变参数模板函数 - 没有歧义?
【发布时间】:2018-11-23 11:26:58
【问题描述】:

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

#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 个 arg 不同?我觉得我可能在某个地方遗漏了一些重要的概念,因为在我的脑海中,上面的示例不应该编译,但显然我错了。

亲切的问候:)

【问题讨论】:

  • Ambiguous call when recursively calling variadic template function overload 的可能副本(编辑:副本的问题略有不同,但答案确实有点迎合这个......)
  • @TrebuchetMS 谢谢你的链接,但我觉得这个问题的答案除了“在我的例子中,不会有歧义”之外并没有真正告诉我什么。我已经知道了。我想知道的是为什么(即如何解决潜在的歧义)
  • 关于 TrebuchetMS 可能的重复链接:这是Jarods answer 解释的(在黄色框中):如果一个函数模板有一个尾随参数包,而另一个没有,则带有省略参数的参数被认为比带有空参数包的参数更专业。这不是回答为什么它适用于最后一个吗?

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


【解决方案1】:

您的代码有问题,但原因不同。正如answer 对相关问题Ambiguous call when recursively calling variadic template function overload 所述,您的代码中的第二个重载被认为更专业。但是,它应该出现在 带有参数包的例程之前。使用 gcc 8.2.1 或 clang 6.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()

从错误中可以看出,即使get_arg_types 有一个参数,编译器也会选择第一个重载,然后调用get_arg_types 而不带参数。一个简单的解决方案是将带有单个参数的get_arg_types 的重载移到带有模板参数包的例程之前,或者在通用例程之前添加一个单参数get_arg_types 的声明。

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-23
    • 1970-01-01
    • 1970-01-01
    • 2013-08-04
    • 2012-05-17
    • 2016-12-11
    相关资源
    最近更新 更多