【问题标题】:Simultaneous use of overloading of parameter and overloading of return type同时使用参数重载和返回类型重载
【发布时间】:2014-01-05 12:01:24
【问题描述】:

我正在尝试制作一个程序,它会自动检测用户输入的数据类型。 我的做法:

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& i)消除旧的歧义 声明 int 输入(istream& i)”。

我不明白,这是如何产生歧义的。是因为,这两个不同的函数(showval 和input)是相互依赖的吗?

在阅读了几篇关于重载的文章后,我意识到在 C++ 中,方法只有在参数不同时才能被重载。 然而this link 有一个技巧,他可以通过返回类型重载函数。是否可以在我的程序中使用相同的技巧?另外,有什么方法可以告诉编译器函数input 具有依赖于用户的参数,并且它的数据类型可能不同,也可能不同。 C++ 是否禁止这种可能性?

【问题讨论】:

    标签: c++ compiler-construction overloading return-type


    【解决方案1】:

    假设int 和float 等类型是特定的,而链接问题中显示的代理对象等类型是通用。我们的选项首先是特定,在这种情况下,我们只是顺其自然,或者我们产生一个通用类型并处理所有各种我们可能支持的特定类型。

    链接问题中显示的代理对象是variant type 的示例,boost::variant 是此的通用实现。例如,boost::variant&lt;int, float&gt; 允许我们持有int 或float。

    我的建议真的取决于你想要什么。你呢

    1. 想要指定您希望从用户那里获得的类型并抛出意外的输入? (具体开始并滑行)或者,
    2. 想要根据用户输入的内容产生不同的类型并指定一组您可以处理的类型? (产生一个通用类型并处理各种特定类型)

    指定您期望用户提供的类型

    在这种情况下,我们可以简单地将函数模板化,并通过模板参数指定我们期望的类型。

    显示的示例保持完全通用,但您可以使用各种技术限制模板参数。查看 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&lt;int, float&gt;。

    #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&lt;int, float&gt;,并处理各种特定类型int和float,在来访者。

    【讨论】:

    • +1 表示变体类型和词法分析器。这是我一直在寻找的实际东西。老实说,我正在寻找指定类型(您的第一个选项)。但是您的第二个选项非常有用且很有帮助。它真的改变了我希望我的程序运行的方式。非常感谢。
    【解决方案2】:

    问题是编译器不可能知道要调用哪个版本的input。只有在 input 中,您实际上尝试从流中提取,并且只有在这一点上,您才能知道用户输入了什么。即使这样,用户也没有理由不能输入1.5,然后您提取到int,或者他们输入5,然后您提取到float。

    类型是编译时构造。编译器使用类型信息来生成程序可执行文件,因此它必须在编译时(在用户输入任何内容之前)知道正在使用的类型。

    所以不,你不能这样做。您可以从输入中提取一行,对其进行解析以确定它是浮点值还是整数(是否有.?),然后为每种情况设置单独的执行路径.但是,我建议您确定您期望用户提供的输入是什么(int 或 float?),然后将其提取出来。

    而且不,代理的技巧对你不起作用。首先,正如我所提到的,输入的格式在编译时是未知的。但其次,在该代码中,所需的类型由声明的变量的类型知道。在一行中,他们执行了int v = ...,而在另一行中,他们执行了double u = ...。在您的情况下,您将结果传递给showval,这可能需要int 或double,编译器不知道是哪个。

    【讨论】:

    • 感谢您的回答。它消除了我的大部分疑虑,除了我的最后一个问题。难道真的不可能改变编译器的行为吗?
    猜你喜欢
    • 2010-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-23
    相关资源
    最近更新 更多