2

我正在尝试编写一个简单的函数,它将从用户输入中获取一个范围内的数字。

当实例化这个函数时,我明确告诉它我希望它实例化,int但我仍然得到错误:

thermo.cpp:105:31: error: no matching function for call to ‘getInput(int&)’

为什么要试图找到一个int&作为参数的函数?

template<class T, T min = std::numeric_limits<T>::min, T max = std::numeric_limits<T>::max>
T getInput(T default_value = T()){
  std::string input;
  T myNumber = T(); //default inits
  while(true){
    getline(cin, input);

    if(input.length() == 0){
      return default_value;
    }

    // This code converts from string to number safely.
    stringstream myStream(input);
    if (myStream >> myNumber){
      if(myNumber > max || myNumber < min){
        stringstream ss;
        ss << "Input out of bounds. Received " << myNumber << " expected between " << min << " and " << max << ".";
        throw invalid_argument(ss.str());
      }
      return myNumber;
    }

    cout << "Invalid number, please try again" << endl;
  }
}

void get(const std::string& prompt, int& param){
  cout << prompt << " [" << param << "]:";
  param = getInput<int,0>(param); // i specifically tell it i want 'int', why am i getting 'int&'?
}

更新

如果我尝试 CharlesB 的建议:

void get(const std::string& prompt, int& param){
  cout << prompt << " [" << param << "]:";
  param = getInput<int,0>(int(param));
}

我明白了

thermo.cpp:105:36: 错误:没有匹配函数调用'getInput(int)'</p>

忘记:

cygwin下的g++ 4.5.3

命令行:

$ g++ thermo.cpp -o thermo.exe -Wall -pedantic -std=c++0x

更新 2

如果我这样称呼它

void get(const std::string& prompt, int& param){
  cout << prompt << " [" << param << "]:";
  param = getInput<int,0,15>(int(param)); // fully parameterized
}

numeric_limits它有效......但我宁愿不在每次调用中指定上限(甚至不指定)。

4

4 回答 4

3

不要为minand使用模板max

template<class T>
T getInput(T default_value = T(), T min = std::numeric_limits<T>::min(), T max = std::numeric_limits<T>::max());

没有理由为这些参数使用模板(除了它不起作用的事实)。

编辑:您不能将这些参数用作模板值,因为std::numeric_limits<T>::min()它是一个函数,它的值在运行时是已知的,并且模板值参数必须在编译时绑定到一个值。这是有效的:

template<class T, T min = 0, T max = 5>
T getInput(T default_value);

因为 0 和 5 在编译期间是已知的。

于 2012-05-14T12:44:03.333 回答
2

我不知道这是否问题所在,但我无法想象它会有所帮助。这一行:

template<class T, T min = std::numeric_limits<T>::min, T max = std::numeric_limits<T>::max>

...使用 min/max 作为值,当它们真的是函数时。也许这会混淆模板参数?

于 2012-05-14T12:45:35.467 回答
2

错误代码并不代表您的想法。错误代码是以下内容的简写:

没有匹配的函数调用getInputint可修改的左值表达式作为单个参数

在这种情况下,int可修改的左值表达式是您用来进行调用param的表达式的类型。现在的问题是,这种格式的错误代码输出非常冗长,仅使用两三个非平凡类型的参数就会变得非常难以阅读,因此编译器会压缩错误报告并告诉您:

没有匹配的函数调用getInput(int&),请注意这里int&不是将被调用的函数的类型,因为编译器无法找到这样的函数,而是调用中使用的参数的类型。

如果您执行 CharlesB 建议的更改,那么您将收到一条不同的错误消息,指出它 cannot find getInput(int)。这里的区别是int(param)创建了一个临时的(右值表达式),所以现在错误反映了它。需要一个不同的错误代码是因为如果你有一个getInput(int&)函数,在第二种情况下,这个重载就不能使用。

关于您收到该错误代码的原因,基本问题是std::numeric_limits<T>::max不是 type T。您的问题是 SFINAE 的基础:您已经定义了一个模板,该模板将作为第二个和第三个参数T,并且T应该使用std::numeric_limits<T>::min(and max) 进行初始化。现在,当编译器尝试确定要调用的函数时,它会找到该模板,使用Tfor int(您提供了确切的类型),0用于 min,然后尝试推断最后一个参数。此时它将尝试T通过默认模板参数获取一个值(最后一个模板参数),方法是将已知模板参数替换为:std::numeric_limits<T>::max。问题是这std::numeric_limits<int>::max不是一个int,而是静态成员函数,因此类型不匹配,导致替换失败。该语言确定替换失败不是错误SFINAE),它仅意味着此模板将从函数调用的候选列表中删除。因为没有其他匹配的重载,编译器放弃并告诉您它找不到匹配的调用函数。

在 C++11 中,您可以使用std::numeric_limits<T>::max(),因为该函数被标记为 a const_expr,因此可以调用以获得T可用作模板参数的类型的常量表达式,但如果您使用的是 C++03 编译器,您将需要以不同的方式解决该问题,例如将minand移动max到函数的默认参数,或者提供从用户获取值或将调用函数的不同重载(std::numeric_limist<T>::max如果参数不存在,则默认为,但后一种选择更麻烦。

于 2012-05-14T13:17:43.657 回答
1

模板函数用参数类型实例化,并且param是一个int&.

宁可做

 param = getInput(int(param));

min 和 max 也不能是模板参数,模板参数是类、类型名或 POD。

于 2012-05-14T12:22:13.173 回答