简体   繁体   English

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

[英]Changing return type of a function without template specialization. C++

I was wondering if it is possible to change the return type of a function based on the type of variable it is being assigned to. 我想知道是否可以根据分配给它的变量类型来更改函数的返回类型。 Here's a quick example of what I mean. 这是我的意思的一个简单例子。

I want to create a function that parses a variable of int, bool, or float from a string. 我想创建一个从字符串中解析int,bool或float变量的函数。 For example... 例如...

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

I understand if I make this function a template, that the variable type must be determined from the argument list which is always going to be a string. 我理解如果我将此函数设为模板,则必须从参数列表中确定变量类型,该列表始终是一个字符串。 Is there any other way of doing this with c++? 用c ++还有其他方法吗?

This can be done with a conversion function 这可以通过转换功能完成

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); }

Now you just need to do 现在你只需要做

float a = parse("3.1");

And it should work well. 它应该运作良好。 Incidentally, you may just use the class directly. 顺便说一句,您可以直接使用该类。 I recommend renaming it to conversion_proxy to point to the fact that it's just a proxy to a happening conversion but that it itself doesn't do conversion 我建议将其重命名为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"); 

I can't tell from your question if you know this or not, but you can indeed do this with a template. 如果您知道这一点,我无法从您的问题中判断出来,但您确实可以使用模板进行此操作。 The only catch is that you will have to specify the type that you are converting from in each invocation instead of relying on inference (since as you said the argument type will always be the same). 唯一的问题是,您必须在每次调用时指定要转换的类型,而不是依赖于推理(因为正如您所说,参数类型将始终相同)。

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.

And then invoke as 然后调用为

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

If you already knew this just ignore this answer, but it's not clear from your question that you are aware that this is possible. 如果您已经知道这个,请忽略这个答案,但从您的问题中不清楚您是否知道这是可能的。

Of course, if what you're doing isn't really generic (and so you have to specialize for each type you want to parse) then writing a template isn't the right thing to do anyway. 当然,如果您正在做的事情并不是真正的通用(因此您必须专门针对您要解析的每种类型),那么编写模板无论如何都不是正确的事情。

By the way, you can do it pretty generically with a single function like this (assuming parse is what you really want to do): 顺便说一下,你可以通过这样的单一函数来做到这一点(假设解析是你真正想要做的):

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

This will work for any default-constructable, stream-extractable type, which includes all built-ins. 这适用于任何默认可构造的,可流提取的类型,其中包括所有内置函数。

You could pass your output argument as a pointer or reference. 您可以将输出参数作为指针或引用传递。

Like this: 像这样:

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

Then code like this: 然后像这样的代码:

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

should work. 应该管用。

However, your code looks like a perfect fit for an std::istringstream that would just be: 但是,您的代码看起来非常适合std :: istringstream,它只是:

istringstream is(input);
input >> d;

If you have somewhat complicated formatting involved, a trick I have had pretty good luck with involves creating custom objects with custom operator>> that pulls out data. 如果你有一些复杂的格式,我有一个非常好运的技巧涉及使用自定义运算符>>拉出数据创建自定义对象。

Then it could be like: 那可能是这样的:

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

I would agree with litb who was a little quicker than myself. 我同意litb比我自己快一点。 Use the casting operators. 使用铸造操作员。

#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;
}

Unfortunately, that isn't possible. 不幸的是,这是不可能的。 In C++ it is not possible to overload a function based on it's return value. 在C ++中,不可能根据函数的返回值重载函数。 You either have to have 3 functions, ParseInt, ParseFloat, and ParseBool, or use a function template. 您必须具有3个函数,ParseInt,ParseFloat和ParseBool,或使用函数模板。

You could return void* and then cast the result as needed. 您可以返回void *,然后根据需要转换结果。

I advise against this though. 我建议不要这样做。 C++ is a strongly typed language. C ++是一种强类型语言。 The advantage of this is that the compiler can catch errors earlier than a dynamically typed language. 这样做的好处是编译器可以比动态类型语言更早地捕获错误。

No this type of behavior is not possible in C++. 在C ++中不可能出现这种类型的行为。 To be allowable it would necessitate being able to define functions of the same name at the same scope that differed only by return type. 为了允许,必须能够在相同的范围内定义相同名称的函数,这些函数仅与返回类型不同。 This is not legal in C++. 这在C ++中是不合法的。

C++ can do some return type specialization such as covariant return types on overridden virtual functions. C ++可以在重写的虚函数上执行一些返回类型特化,例如协变返回类型。 But it does not support what you are looking for. 但它不支持您正在寻找的东西。

Here's my adaptation of @Tyler McHenry's answer for my situation where the argument to parse() is a type other than a string. 这是我改编的@Tyler McHenry对我的情况的回答 ,其中parse()的参数是一个字符串以外的类型。

Note that I found I had to introduce a template specialization in order to avoid a type conversion warning ( float to int ). 请注意,我发现我必须引入模板特化以避免类型转换警告float to int )。

(Also see 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'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM