为什么模板试图与'int&'进行实例化而不是'int'?

时间:2012-05-14 12:19:20

标签: c++ templates

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

当实现此功能时,我明确地告诉它我希望它与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)'

忘记:

  

gg 4.5.3在cygwin下

命令行:

  

$ 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 个答案:

答案 0 :(得分:3)

请勿使用minmax的模板:

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在编译期间是已知的。

答案 1 :(得分:2)

我不知道这是否是 问题,但我无法想象这有什么帮助。这一行:

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

...将min / max用作值when they're really functions。也许这会让模板参数混淆不清?

答案 2 :(得分:2)

错误代码并不代表您的想法。错误代码是:

的简写

没有匹配函数调用getInput,它将int可修改的左值表达式作为单个参数

其中 int可修改的左值表达式是您在此案例param中用于进行调用的表达式的类型。现在问题是这种格式的错误代码输出是非常冗长的,只用两个或三个非平凡类型的参数就很难读取,所以编译器会压缩错误报告并告诉你:

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

如果您执行CharlesB建议的更改,那么您将收到一条不同的错误消息,指出它无法找到getInput(int)。这里的区别在于int(param)创建了一个临时( rvalue表达式),因此错误现在反映了它。需要一个不同的错误代码来自这样一个事实:如果你有getInput(int&)函数,在第二种情况下,不能使用该重载。

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

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

答案 3 :(得分:1)

模板函数使用参数类型进行实例化,paramint&

宁可做

 param = getInput(int(param));

min和max也不能是模板参数,模板参数是class,typename或POD。