我目前正在研究可变参数模板,并且作为一个摘要练习来消化我一直在阅读的某些内容,我编写了一个小函数来输出其所有参数类型的名称:
#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不一致?我觉得我可能在某个地方错过了一些重要的概念,因为在我看来,上面的示例不应该编译,但是显然我错了。
亲切的问候:)
答案 0 :(得分: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();
}
同样,应在模板例程之前放置(或至少声明)这样的专业化名称。请注意,在第二种解决方案中,输出会稍有变化。