同时使用参数重载和返回类型的重载

时间:2014-01-05 12:01:24

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

我试图创建一个程序,它自动检测用户给出的输入数据类型。 我的方法:

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)“。

我不明白,这是如何造成歧义的。是因为,两个不同的函数(showvalinput)是否依赖?

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

2 个答案:

答案 0 :(得分:1)

问题是编译器不可能知道要调用哪个版本的input。您实际上只是尝试从流中提取 input内的,并且只有在此时您才能知道用户输入的内容。即使这样,用户也无法输入1.5,然后您将其提取到int,或者他们输入5并提取到float。< / p>

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

所以不,你不能这样做。你可以从输入中提取一行,解析它以确定它是浮点值还是整数(它是否有.?),然后有一个单独的执行路径每个案例。但是,我建议您决定从用户那里得到的输入是什么(int还是float?),然后只提取它。

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

答案 1 :(得分:1)

假设intfloat等类型特定,链接问题中显示的代理对象等类型泛型。我们的选择是具体开始,在这种情况下,我们只是浏览其余部分,或者我们产生泛型类型并处理所有各种我们可能支持的具体类型。

链接问题中显示的代理对象是variant type的示例,boost::variant是此的一般实现。例如,boost::variant<int, float>允许我们按住intfloat

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

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

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

    显示的示例完全保持通用,但您可以使用各种技术限制模板参数。查看有关此主题的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.01.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,并为float1.之类的输入产生1.0 { {1}}。

    如您所见,我们会产生通用类型1.2,并处理各种特定类型boost::variant<int, float>和{ {1}},在访客中。