15

我想知道是否可以根据分配给它的变量类型来更改函数的返回类型。这是我的意思的一个快速示例。

我想创建一个函数来解析字符串中的 int、bool 或 float 变量。例如...

Int value = parse("37");
Float value = parse("3.14");
Bool value = parse("true");

我知道如果我将此函数设为模板,则必须从始终为字符串的参数列表中确定变量类型。有没有其他方法可以用 c++ 做到这一点?

4

8 回答 8

32

这可以通过转换函数来完成

struct proxy {
    string str;
    proxy(string const &str):str(str) { }
    template<typename T> operator T() { 
        return boost::lexical_cast<T>(str); 
    }
};

proxy parse(string const &str) { return proxy(str); }

现在你只需要做

float a = parse("3.1");

它应该运作良好。顺便说一句,您可以直接使用该类。我建议将其重命名为conversion_proxy以表明它只是正在发生的转换的代理,但它本身不进行转换

struct conversion_proxy {
    string str;
    conversion_proxy(string const &str):str(str) { }
    template<typename T> operator T() { 
        return boost::lexical_cast<T>(str); 
    }
};

float a = conversion_proxy("3.1"); 
于 2009-06-18T03:28:39.573 回答
12

我无法从您的问题中判断您是否知道这一点,但您确实可以使用模板来做到这一点。唯一的问题是,您必须在每次调用中指定要转换的类型,而不是依赖推理(因为正如您所说,参数类型将始终相同)。

template<typename T> T parse(const string& str) { /* do stuff for other types */ }
template<> int parse<int>(const string& str) { /* do stuff for ints */ }
template<> double parse<double>(const string& str) { /* do stuff for doubles */ }
template<> bool parse<bool>(const string& str) { /* do stuff for bools */ }
// etc.

然后调用为

int value = parse<int>("37");
double value = parse<double>("3.14");
bool value = parse<bool>("true");

如果您已经知道这一点,请忽略此答案,但从您的问题中不清楚您是否知道这是可能的。

当然,如果您正在做的事情不是真正通用的(因此您必须专门针对要解析的每种类型),那么编写模板无论如何都不是正确的事情。

顺便说一句,您可以使用这样的单个函数非常通用地完成它(假设 parse 是您真正想要做的):

#include <sstream>
template<typename T> T parse(const string& str) 
{
  T t;
  std::istringstream sstr(str);
  sstr >> t;
  return t;
}

这适用于任何默认可构造、可流提取的类型,包括所有内置函数。

于 2009-06-18T03:01:34.277 回答
5

您可以将输出参数作为指针或引用传递。

像这样:

template<class T> void parse(const std::string &input, T& output);

然后这样的代码:

double d; parse(input, d);
int i; parse(input, i);

应该管用。

但是,您的代码看起来非常适合 std::istringstream ,它只是:

istringstream is(input);
input >> d;

如果你有一些复杂的格式,我很幸运的一个技巧是使用自定义操作符>>创建自定义对象来提取数据。

那么它可能是这样的:

istringstring is(input);
input >> LineExtracter(x, y, d);
于 2009-06-18T03:21:20.257 回答
4

我会同意比我快一点的 litb。使用铸造运算符。

#include <iostream>
#include <string>
#include <sstream>

class Convertible
{
public:
    int m_Integer;
    bool m_Bool;
    double m_Double;

    Convertible() : m_Integer(0), m_Bool(false), m_Double(0.0) {};

    operator int() const
    {
        return m_Integer;
    }
    operator bool() const
    {
        return m_Bool;
    }
    operator double() const
    {
        return m_Double;
    }
};

Convertible parse(std::string data)
{
    Convertible l_result;

    std::istringstream converter(data);
    converter >> l_result.m_Integer;

    std::istringstream converter2(data);
    converter2 >> l_result.m_Bool;

    std::istringstream converter3(data);
    converter3 >> l_result.m_Double;

    return l_result;
}

void main()
{
    int l_convertedInt = parse("2");
    bool l_convertedBool = parse("true");
    double l_convertedDouble = parse("3.14");

    std::cout << "Converted '2' to " << l_convertedInt << std::endl;
    std::cout << "Converted 'true' to " << l_convertedBool << std::endl;
    std::cout << "Converted '3.14' to " << l_convertedDouble << std::endl;
}
于 2009-06-18T03:34:41.650 回答
0

不幸的是,这是不可能的。在 C++ 中,不可能根据函数的返回值重载函数。您要么必须拥有 3 个函数,ParseInt、ParseFloat 和 ParseBool,要么使用函数模板。

于 2009-06-18T02:53:33.620 回答
0

您可以返回 void* 然后根据需要转换结果。

我建议不要这样做。C++ 是一种强类型语言。这样做的好处是编译器可以比动态类型语言更早地捕获错误。

于 2009-06-18T02:56:49.433 回答
0

不,这种行为在 C++ 中是不可能的。为了允许,它必须能够在相同的范围内定义相同名称的函数,这些函数仅在返回类型上有所不同。这在 C++ 中是不合法的。

C++ 可以做一些返回类型的特殊化,例如覆盖虚函数的协变返回类型。但它不支持您要查找的内容。

于 2009-06-18T03:16:28.943 回答
0

这是我对@Tyler McHenry 的答案的改编,适用于我的情况,其中的参数parse()是字符串以外的类型。

请注意,我发现我必须引入模板专业化以避免类型转换警告floatto int)。

(另见现场演示。)

#include <iostream>

struct MyUnion
{
public:
  union {
    bool bool_value;
    int int_value;
    float float_value;
  };
};

template<typename T> T parse(const MyUnion& h)
{
  T t;

  if (typeid(T) == typeid(bool)) {
    t = h.bool_value;
  } else if (typeid(T) == typeid(int)) {
    t = h.int_value;
  } else if (typeid(T) == typeid(float)) {
    // t = h.float_value; // see **Warning** below; use float specialization instead
  }

  return t;
}

// 'float' template specialization to avoid conversion warning.
template<> float parse(const MyUnion& h)
{
  return h.float_value;
}

int main()
{
  MyUnion mu1; mu1.bool_value = true;
  MyUnion mu2; mu2.int_value = 42;
  MyUnion mu3; mu3.float_value = 3.14159;

  std::cout << "As bool: "  << parse<bool>(mu1)  << std::endl;
  std::cout << "As int: "   << parse<int>(mu2)   << std::endl;
  std::cout << "As float: " << parse<float>(mu3) << std::endl;
}

// **Warning**
// In function 'T parse(const Heterogeneous&) [with T = int]':
// Line 22: warning: converting to 'int' from 'const float'
于 2013-03-09T03:31:00.850 回答