int x = fromString("test")
:无法推导出 'ValueType' 的模板参数
int x = fromString<int>("test")
:按预期正常工作。
那么编译器为什么会有问题呢?我在各种真实的模板函数中都遇到了这个问题,而不仅仅是这个愚蠢的例子。这一定是语言的一个特性,但是它是什么呢?
你不能根据返回类型进行推断。但是,你可以使用重载的强制类型转换运算符实现类似语法的解决方法:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
class FromString{
private:
string m_data;
public:
FromString(const char*data) : m_data(data) {}
template<typename T>
operator T(){
T t;
stringstream ss(m_data);
ss >> t;
return t;
}
};
template<> FromString::operator bool(){
return (m_data!="false"); //stupid example
}
int main(){
int ans = FromString("42");
bool t = FromString("true");
bool f = FromString("false");
cout << ans << " " << t << " " << f << endl;
return 0;
}
输出:
42 1 0
operator=
不能是friend
,我想这是最好的解决方案,+1。 - PotatoswatterC++不会对返回值进行类型推断,也就是说,分配给int类型并不会在模板参数推导中使用。
(已删除编辑,因为其他人已经提供了过载强制转换的解决方案。)
看起来你的模板有模板化的返回类型,这种类型无法自动推断,所以你需要在这里添加它。
int x = to<int>("1235")
而不是toString
),问题在于返回类型不参与重载解析或类型推断[1]。原因是该表达式可以用于许多无法推断返回类型的地方:
// assuming template <typename T> T to( std::string ):
//
f( to("123") ); // where there are two overloads f(int), f(double)
int x = 1.5 * to("123"); // T == int? T == double?
to("123"); // now what? returned object can be ignored!
因此,决定是返回类型不参与重载解析或类型推导。
[1] 这个规则有一个例外,即对具有多个重载的函数指针进行评估时,必须通过目标指针或显式转换来选择重载,但这只是一个例外,在任何其他情况下都不使用:
void f();
void f(int);
void g( void (*)() );
void g( void (*)(int) );
void (*p1)() = &f; // overload selected based on destination type
void (*p2)(int) = &f;
g( (void (*)(int))&f ); // overload selected based on explicit cast
函数的返回类型取决于重载决议,而不是相反。
然而有一个技巧可行:通常只有等式左右两边参数类型相等时才存在operator=
,除非定义了显式的operator=
(无论是作为独立函数还是成员函数都可以)。
因此,重载决议将找到operator=(int &, int)
,并查看您的函数返回值是否可转换为int。如果您返回一个具有operator int
的临时对象,则这是一种可接受的解决方案(即使operator int
以template<typename T> operator T
的通用形式出现)。
因此:
template<typename T, typename U>
U convert_impl(T const &t);
template<typename T>
struct convert_result {
convert_result(T const &t) : t(t) { }
template<typename U> operator U(void) const { return convert_impl<U>(t); }
T const &t;
};
template<typename T>
convert_result<T> convert(T const &t) { return t; }
template <typename T> T doubleit(T t) { return 2*t; }
。现在,int i = doubleit(0.5);
是否调用doubleit<int>
(以匹配i
)或者doubleit<double>
(以匹配0.5
)?结果是不同的,因此即使该语言有解决歧义的规则,读取代码的任何人都很容易犯错。让子表达式的类型和含义仅依赖于子表达式本身,而不依赖于周围的表达式,至少是简单的。 - Steve Jessop