c++ - 主函数体未检测到对重载可变参数模板函数 C++ 的调用
问题描述
我目前正在学习可变参数模板函数和参数打包/解包。
这是我的代码,
template<typename T, typename U>
void my_insert(std::vector<int>& v, T& t) {
int i;
if (typeid(t).name() == typeid(const char*).name()) {
i = stoi(t);
}
else if (typeid(t).name() == typeid(char).name()) {
i = t - 48;
}
else if (typeid(t).name() == typeid(int).name()) {
i = t;
}
else if (typeid(t).name() == typeid(double).name()) {
i = static_cast<int>(round(t));
}
else if (typeid(t).name() == typeid(bool).name()) {
if (t) i == 1;
else i == 0;
}
else if (typeid(t).name() == typeid(std::vector<U>).name()) {
int j = 0;
while (j < t.size()) {
my_insert(v, t[j]);
++j;
}
}
else return;
v.push_back(i);
}
template<typename T, typename U, typename ...Args>
void my_insert(std::vector<int>& v, T& t, Args&... args) {
int i;
if (typeid(t).name() == typeid(const char*).name()) {
if (isdigit(t[0])) i = stoi(t);
// else do nothing
}
else if (typeid(t).name() == typeid(char).name()) {
i = t - 48;
}
else if (typeid(t).name() == typeid(int).name()) {
i = t;
}
else if (typeid(t).name() == typeid(double).name()) {
i = static_cast<int>(round(t));
}
else if (typeid(t).name() == typeid(bool).name()) {
if (t) i == 1;
else i == 0;
}
else if (typeid(t).name() == typeid(std::vector<U>).name()) {
int j = 0;
while (j < t.size()) {
my_insert(v, t[j]);
++j;
}
}
//else do nothing
v.push_back(i);
my_insert(args...);
}
int main() {
std::vector<int> v;
my_insert(v, "123", "-8", 32, 3.14159, true, true, false, '5', "12.3");
return 0;
}
错误:没有重载函数 my_insert 的实例与参数列表匹配
print()
我不明白我犯了什么错误,因为对我来说,a函数的完全相同的实现可以使用{ cout << t << endl; print(args...); }
,带签名<typename T, typename ...Args> void print(const T& t, const Args... args)
;
我知道可变参数函数可以通过递归调用同一函数的非可变参数重载版本来实现。所谓的基本案例陈述。
说了这么多,我不确定我做错了什么。
解决方案
嗯......你的代码中有一些问题。
阻塞错误是模板参数U
template<typename T, typename U>
void my_insert(std::vector<int>& v, T& t)
template<typename T, typename U, typename ...Args>
void my_insert(std::vector<int>& v, T& t, Args&... args)
编译器无法推断并调用函数
my_insert(v, "123", "-8", 32, 3.14159, true, true, false, '5', "12.3");
没有U
解释
我想这个想法是“如果T
是std::vector
某种类型U
,则添加向量的所有元素”。如果我理解正确,我建议添加该函数的不同重载版本。
其他问题...
1)在几个点你写一些东西
if (t) i == 1;
else i == 0;
在我看来,您使用运算符==
(比较)而不是=
(分配)。
一般建议:启用最高警告级别来拦截此类微不足道的错误。
2) 你的使用typeid
if (typeid(t).name() == typeid(char).name())
比较类型。
建议:std::is_same
改用
if ( std::is_same<T, char>::value )
3)递归的基本情况是一个my_insert()
与递归版本几乎相同的函数;唯一的区别是没有Args...
参数和递归调用。
这很容易出错,因为如果您修改两个版本中的一个,您必须记住以相同的方式修改另一个。
建议:写一个空无一物的地面案例;某事作为
void my_insert (std::vector<int> & v)
{ }
4)你不能编译
i = stoi(t);
什么时候t
不是char const *
其他作业的类似问题。
问题是当你写[伪代码]
if ( condition )
statement_1;
else
statement_2;
编译器必须同时编译statement_1
并且statement_2
知道编译时间condition
是true
or false
。
为避免编译未使用的语句,您必须使用if constexpr
.
所以你必须写一些东西
if constexpr ( std::is_same_v<T, char const *> )
i = std::stoi(t);
else if constexpr ( std::is_same_v<T, char> )
i = t - 48;
else if constexpr ( std::is_same_v<T, int> )
i = t;
else if constexpr ( std::is_same_v<T, double> )
i = static_cast<int>(std::round(t));
else if constexpr ( std::is_same_v<T, bool> )
i = t;
不幸的是,if constexpr
仅从 C++17 开始可用。
在 C++17 之前,你必须编写不同的重载函数。
5)my_insert()
递归调用,你要记住v
向量
my_insert(args...); // <-- wrong! no v
my_insert(v, args...); // <-- correct
6) 考虑"123"
可转换为char const *
但不是 a char const *
(它是 a char const [4]
) 的计数;所以,而不是
if constexpr ( std::is_same_v<T, char const *> )
i = std::stoi(t);
你可以试试
if constexpr ( std::is_convertible_v<T, char const *> )
i = std::stoi(t);
以下是您的代码的可能 C++17 实现
#include <cmath>
#include <string>
#include <vector>
#include <iostream>
void my_insert (std::vector<int> const &)
{ }
template <typename T, typename ... As>
void my_insert (std::vector<int> &, std::vector<T> const &, As const & ...);
template <typename T, typename ... As>
void my_insert (std::vector<int> & v, T const & t, As const & ... as)
{
int i{};
if constexpr ( std::is_convertible_v<T, char const *> )
i = std::stoi(t);
else if constexpr ( std::is_same_v<T, char> )
i = t - 48;
else if constexpr ( std::is_same_v<T, int> )
i = t;
else if constexpr ( std::is_same_v<T, double> )
i = static_cast<int>(std::round(t));
else if constexpr ( std::is_same_v<T, bool> )
i = t;
// else ???
v.push_back(i);
my_insert(v, as...);
}
template <typename T, typename ... As>
void my_insert (std::vector<int> & v, std::vector<T> const & t,
As const & ... as)
{
for ( auto const & val : t )
my_insert(v, val);
my_insert(v, as...);
}
int main ()
{
std::vector<int> v;
std::vector<char> u { '9', '8', '7' };
my_insert(v, "123", "-8", 32, 3.14159, true, u, false, '5', "12.3");
for ( auto const & val : v )
std::cout << val << ' ';
std::cout << std::endl;
}
推荐阅读
- laravel - 使用 Event::fake() 或 Queue::fake() 时通知测试失败
- bootstrap-4 - 文本和图像与引导程序并排
- python - Python将日期时间转换为秒
- android-studio - 应用程序在模拟器上运行但在我的手机上崩溃
- scala - scala类型与短裤和乘法不匹配
- c# - 有什么方法更容易绑定到视图模型中的点击事件?
- html - CSS 背景图像未显示在 GitHub 页面上?
- node.js - 如何检查对象是否是 Node.js 中的 SocketIO.Socket 或 net.Socket 的实例?
- configuration - log4j2 + 以编程方式覆盖 Web 应用程序中的父自定义 ConfigurationFactory
- javascript - 是否可以在加载完成之前捕获 iframe 窗口?