在没有模板专门化的情况下更改函数的返回类型。 C ++

时间:2009-06-18 02:52:13

标签: c++ templates return

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

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

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

我理解如果我将此函数设为模板,则必须从参数列表中确定变量类型,该列表始终是一个字符串。用c ++还有其他方法吗?

8 个答案:

答案 0 :(得分:31)

这可以通过转换功能

完成
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"); 

答案 1 :(得分: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");

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

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

顺便说一句,你可以通过这样的单一函数来做到这一点(假设解析是你真正想做的事情):

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

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

答案 2 :(得分: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;

如果你有一些复杂的格式,我有一个相当不错的技巧涉及使用自定义运算符创建自定义对象&gt;&gt;拉出数据。

然后它可能会像:

istringstring is(input);
input >> LineExtracter(x, y, d);

答案 3 :(得分:3)

我同意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;
}

答案 4 :(得分:0)

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

答案 5 :(得分:0)

您可以返回void *,然后根据需要投射结果。

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

答案 6 :(得分:0)

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

C ++可以在重写的虚函数上执行一些返回类型特化,例如协变返回类型。但它不支持您正在寻找的东西。

答案 7 :(得分:0)

这是我对@Tyler McHenry's answer的改编,我的情况是parse()的参数是一个字符串以外的类型。

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

(另见live demo。)

#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'