假设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));
}
这将为1 等输入产生int,甚至对于1.、1.0 和1.2 等输入。
处理您可能从用户那里获得的不同类型
在这种情况下,我们实际上是在对来自用户的输入流进行词法分析。我们的read 函数会产生一个generic 类型,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));
}
这种方法会为1 等输入生成int,并为1.、1.0 等输入生成float1.2。
如您所见,我们产生了一个通用类型boost::variant<int, float>,并处理各种特定类型int和float,在来访者。