在函数模板中转换类型

时间:2016-07-21 15:16:10

标签: c++

我有一个函数模板,它通过模板定义的引用变量给出结果。 此函数必须转换值并分配给引用变量。 我在代码中显示的行中编译有问题。

有什么问题,我该如何解决?

以下是我的代码:

#include "stdafx.h"
#include <iostream>
#include <string>
#include <map>

using namespace std;

map<wstring, wstring> my_data = {
    { L"data1", L"123.456"  },
    { L"data2", L"2213.323" },
    { L"data3", L"3321.321" },
    { L"data4", L"1000" },
    { L"data5", L"2000" }
};



template<class T>
bool get_map_value(const wstring &map_key, T& map_value)
{
    auto tmp = my_data.find(map_key);

    if (tmp == my_data.end())
        return false;

    if (typeid(T).name() == typeid(wstring).name())
        map_value = tmp->second;
        //Error C2440   '=': cannot convert from 'std::wstring' to 'int'    
        //Error C2440   '=': cannot convert from 'std::wstring' to 'double' 

    else if (typeid(T).name() == typeid(double).name())
        map_value = _wtof(tmp->second.c_str());

    else if (typeid(T).name() == typeid(int).name())
        map_value = _wtoi(tmp->second.c_str());


    return true;
}


int main() {

    double d = 0.0;
    wstring w = L"";
    int i = 0;

    get_map_value(L"data1", w);
    get_map_value(L"data3", d);
    get_map_value(L"data4", i);


    return 0;
}

3 个答案:

答案 0 :(得分:2)

  

出了什么问题

tmp->second的类型为wstring。使用T = int实例化模板时,map_value的类型为int&。这条线

map_value = tmp->second;

有非常自我解释的错误消息

Error C2440   '=': cannot convert from 'std::wstring' to 'int'

std::wstring无法隐式转换为int。那就是问题所在。你必须记住,即使执行不能达到某些部分,整个函数也必须很好地形成。

  

我该如何解决?

您需要的只是一些重载。我们将重构函数的不同部分,以便您不需要重复相同的部分。

parse_value(int& variable, const std::wstring& value) {
    variable = _wtoi(tmp->second.c_str());
}
parse_value(double& variable, const std::wstring& value) {
    variable = _wtof(tmp->second.c_str());
}
parse_value(std::wstring& variable, const std::wstring& value) {
    variable = value;
}

template<class T>
bool get_map_value(const wstring &map_key, T& map_value)
{
    auto tmp = my_data.find(map_key);

    if (tmp == my_data.end())
        return false;

    parse_value(map_value, tmp->second);

    return true;

}

答案 1 :(得分:0)

模板在编译时进行评估。运行时if语句不保护正在运行的代码,因为编译器无法保证不会采用该路径。

从C ++ 17开始,你可以使用constexpr if,但同时,你必须为它编写不同的专业(甚至重载,你甚至不需要模板):

bool get_map_value(const wstring &map_key, wstring& map_value)
{
    auto tmp = my_data.find(map_key);

    if (tmp == my_data.end())
        return false;

    map_value = tmp->second;

    return true;
}

bool get_map_value(const wstring &map_key, double& map_value)
{
    auto tmp = my_data.find(map_key);

    if (tmp == my_data.end())
        return false;

    map_value = _wtof(tmp->second.c_str());    

    return true;
}

bool get_map_value(const wstring &map_key, int& map_value)
{
    auto tmp = my_data.find(map_key);

    if (tmp == my_data.end())
        return false;

    map_value = _wtoi(tmp->second.c_str());

    return true;
}

答案 2 :(得分:0)

首先,删除这些丑陋的typeid() ...然后使用SFINAE。

template <typename T, std::enable_if_t<std::is_floating_point<T>::value>* = nullptr>
bool get_map_value(std::wstring const& map_key, T& map_value) {
    auto const val = std::find(my_data.cbegin(), my_data.cend(), map_key);
    if (val != std::cend(my_data)) {
        map_value = _wtof(val.second);
        return true;
    } else {
        return false;
    }
}

类似地,然后为整数类型添加另一个定义:

template <typename T, std::enable_if_t<std::is_integral<T>::value>* = nullptr>
bool get_map_value(std::wstring const& map_key, T& map_value) {
    auto const val = std::find(my_data.cbegin(), my_data.cend(), map_key);
    if (val != std::cend(my_data)) {
        map_value = _wtoi(val.second);
        return true;
    } else {
        return false;
    }
}

最后是std::wstring的简单重载:

bool get_map_value(std::wstring const& map_key, std::wstring& map_value) {
    auto const val = std::find(my_data.cbegin(), my_data.cend(), map_key);
    if (val != std::cend(my_data)) {
        map_value = val.second;
        return true;
    } else {
        return false;
    }
}