为什么C ++不能从赋值中推断出模板类型?

时间:2011-11-17 10:33:26

标签: c++ templates stl

int x = fromString("test")无法推断'ValueType'的模板参数

int x = fromString<int>("test"):按预期正常工作

为什么编译器在这里挣扎?我用各种真实的模板函数看到它,而不仅仅是这个愚蠢的例子。它必须是语言的一个特征,但是什么?

5 个答案:

答案 0 :(得分:18)

您无法根据返回类型推断出。但是,您可以使用重载的强制转换运算符实现具有类似语法的变通方法:

#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

答案 1 :(得分:12)

C ++不对返回值进行类型推断。即,它被分配给int的事实不用于模板参数推导。

(删除了编辑,因为其他人已经提交了重载的强制转换解决方案。)

答案 2 :(得分:1)

看起来您的模板具有模板化的返回类型,无法自动推断,这就是您需要在此处添加它的原因。

答案 3 :(得分:0)

除了示例的错误选择(可能有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] 此规则有一个例外,即对具有多个重载的函数指针的求值,其中必须通过目标指针或显式选择重载cast,但这只是一个例外,并没有在任何其他上下文中使用:

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

答案 4 :(得分:0)

函数的返回类型取决于重载决策,而不是相反。

有一个技巧可行:operator=通常仅存在于相同的LHS / RHS参数类型,除非定义了显式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; }