我试图创建一个程序,它自动检测用户给出的输入数据类型。 我的方法:
int input(istream& i)
{
int k;
i>>k;
return k;
}
float input(istream& i)
{
float k;
i>>k;
return k;
}
void showval(int h){cout<<h;}
void showval(float h){cout<<h;}
int main()
{
showval(input(cin));
return 0;
}
如您所见,我使用重载参数和重载两种不同函数的返回类型,但同时使用。但是,该程序给出了错误
“新声明浮动输入(istream&amp; i)消除了旧的歧义 声明int输入(istream&amp; i)“。
我不明白,这是如何造成歧义的。是因为,两个不同的函数(showval
和input
)是否依赖?
在阅读了一些关于重载的文章后,我意识到在C ++中,方法只有在参数不同时才会重载。
但是this link 有一个技巧,他可以通过返回类型重载函数。是否有可能在我的程序中使用相同的技巧?另外,有什么方法可以告诉编译器函数input
具有用户相关的参数,并且其数据类型可能有差异,也可能没有差异。 C ++是否禁止这种可能性?
答案 0 :(得分:1)
问题是编译器不可能知道要调用哪个版本的 类型是编译时构造。编译器使用类型信息来生成程序可执行文件,因此它必须知道在编译时使用的类型(在用户输入任何内容之前的方式)。 所以不,你不能这样做。你可以从输入中提取一行,解析它以确定它是浮点值还是整数(它是否有 而且不,代理的技巧对你不起作用。首先,正如我所提到的,无论如何,输入的格式在编译时都是未知的。但其次,在该代码中,所声明的变量的类型已知所需的类型。在一行中,他们input
。您实际上只是尝试从流中提取 input
内的,并且只有在此时您才能知道用户输入的内容。即使这样,用户也无法输入1.5
,然后您将其提取到int
,或者他们输入5
并提取到float
。< / p>
.
?),然后有一个单独的执行路径每个案例。但是,我建议您决定从用户那里得到的输入是什么(int
还是float
?),然后只提取它。int v = ...
,而在另一行,他们做double u = ...
。在您的情况下,您将结果传递给showval
,这可能需要int
或double
,并且编译器不知道哪个。
答案 1 :(得分:1)
假设int
和float
等类型特定,链接问题中显示的代理对象等类型泛型。我们的选择是具体开始,在这种情况下,我们只是浏览其余部分,或者我们产生泛型类型并处理所有各种我们可能支持的具体类型。
链接问题中显示的代理对象是variant type的示例,boost::variant
是此的一般实现。例如,boost::variant<int, float>
允许我们按住int
或float
。
我的建议真的取决于你想要的。你
在这种情况下,我们可以简单地使函数模板化,并通过模板参数指定我们期望的类型。
显示的示例完全保持通用,但您可以使用各种技术限制模板参数。查看有关此主题的my answer。
#include <iostream>
/* Read data of type T from an input stream. */
template <typename T>
T read(std::istream &strm) {
T val;
strm >> val;
if (!strm) {
throw /* something */;
} // if
return val;
}
/* Print data of type T. */
template <typename T>
void print(const T &val) {
std::cout << val;
}
int main() {
print(read<int>(std::cin));
}
这会产生int
输入,例如1
,甚至输入1.
,1.0
和1.2
等。
在这种情况下,我们实际上是来自用户的输入流。我们的read
函数会生成泛型类型boost::variant<int, float>
。
#include <iostream>
#include <boost/variant.hpp>
/* Naive implementation of a lexer. */
boost::variant<int, float> read(std::istream &strm) {
std::string lexeme;
strm >> lexeme;
try {
std::size_t idx;
auto val = std::stoi(lexeme, &idx);
if (idx == lexeme.size()) { // Make sure we converted the entire lexeme.
return val;
} // if
} catch (const std::exception &) {
// Do nothing. We'll try to lex it as float instead.
} // try
std::size_t idx;
auto val = std::stof(lexeme, &idx);
if (idx == lexeme.size()) { // Make sure we converted the entire lexeme.
return val;
} // if
throw /* something */;
}
/* Print the type and the value, to check that we have the correct type. */
void print(const boost::variant<int, float> &val) {
class visitor : public boost::static_visitor<void> {
public:
void operator()(int that) const {
std::cout << "int: " << that << std::endl;
}
void operator()(float that) const {
std::cout << "float: " << that << std::endl;
}
}; // visitor
boost::apply_visitor(visitor(), val);
}
int main() {
print(read(std::cin));
}
此方法会为int
之类的输入产生1
,并为float
,1.
之类的输入产生1.0
{ {1}}。
如您所见,我们会产生通用类型1.2
,并处理各种特定类型boost::variant<int, float>
和{ {1}},在访客中。