【问题标题】:C++ function that conditionally returns different types有条件地返回不同类型的 C++ 函数
【发布时间】:2015-10-22 13:22:08
【问题描述】:

我正在尝试编写一个模板函数,该函数将根据传入的字符串返回不同的类型。

template<typename T>
T test(string type)
{
    int   integer   = 42;
    float floateger = 42.42;

    if (type == "int")
        return integer;
    if (type == "float")
        return floateger;
}

int main()
{

    int integer = test("int");

    cout << "INTEGER: " << integer << endl;
}

当我运行它时,我收到以下错误:

错误:没有匹配的函数调用 'test(const char [4])

我怎样才能实现这样的事情?


我的最终目标是编写一个函数,该函数将根据传入的字符串返回不同类的对象。我知道这可能根本不是正确的方法。这样做的正确方法是什么?

【问题讨论】:

  • 考虑boost::any
  • 看起来你需要多态性
  • 当您意识到这可能不是正确的方法时,您可能应该详细说明您实际尝试做的事情 - 而不是专注于解决问题的方法(以及如何做到这一点)?
  • 不要那样做。你不能。
  • @NeilKirk 先爬再跑。

标签: c++ function templates


【解决方案1】:

你不能那样做,至少不能那样做。

为了能够返回不同的类型,您必须首先通过引用返回,其次可能返回的类型必须从声明的返回类型继承。

例如:

class Base {
};

class Derived1 : public Base {
};

class Derived2 : public Base {
};

Base& func(string type) {
     static Derived1 d1;
     static Derived2 d2;

     if( type == "Derived1" )
         return d1;
     if( type == "Derived2" )
         return d2;

     //etc
}

【讨论】:

  • 好的,现在我返回了一个派生类并将其存储在对基类的引用中......现在如何通过这个引用访问派生类的成员?
  • 叹息。你没有。这就是多态性的要点。您只能访问基类的成员。当成员是虚函数时,成员自己知道该做什么。
  • 可以直接使用Base类的接口。通常,您将拥有在派生类中被覆盖以提供功能的虚拟方法。否则,如果您需要派生类型,您可以使用 dynamic_cast 来转换指针/引用(如果它确实指的是预期类型)。
  • dynamic_cast 听起来可能是我需要的。我会调查的。
【解决方案2】:

函数总是返回相同类型的值。

你可以做的是返回一个指向公共基类的指针:

struct A {};

struct B : A {};

struct C : A {};

A* make(const std::string& s)
{
    if (s == "B")
        return new B;
    else if (s == "C")
        return new C;
    else
        return nullptr;
}

【讨论】:

  • 它可以让我这样做,但是一旦我使用该函数并返回基类,我就无法使用它来访问所选非基类的成员。尝试编译时出现“类 没有名为 的成员”错误。
  • @tjwrona1992 你不能同时拥有“一个或另一个”的东西并且知道它是哪一个。这就是遗传的不确定性原理。如果您关心返回值是哪种类型,那么您正在寻找错误的解决方案。
【解决方案3】:

一般不可能重载返回值,因为编译器不可能解决它。想象一个像下面这样的语句:

your_overloaded_function();

你没有将返回值存储在任何变量中,因为你对它不感兴趣,那么编译器怎么知道你要调用哪个函数呢?它不能,简单地说。

您可以返回层次结构的基类,这确实不是重载的返回值,但它允许您返回不同类的不同实例,从而获得接近您想要实现的目标。

无论如何,有一些技巧可以明确地得到它。它遵循一个可能的使用偏特化的方法:

#include <iostream>
#include <type_traits>

using namespace std;

template<typename T, typename Enable = void>
struct S { };

template<typename T>
struct S<T, typename std::enable_if<std::is_integral<T>::value>::type>
{
    T operator()() { return 42; }
};

template<typename T>
struct S<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
{
    T operator()() { return 42.42; }
};

int main()
{
    S<int> si;
    S<float> sf;
    int integer = si();
    float float_ = sf();
    cout << "INTEGER: " << integer << endl;
    cout << "FLOAT: " << float_ << endl;
}

也就是说,这是一个涉及 integerfloat 的 sn-p,如您的示例所示。

无论如何,要做到我认为你想做的事,你可以依赖像 abstract factorycreational patterns 这样的众所周知的模式作为示例,而不是依赖模板.

【讨论】:

  • 你可能已经猜到我不是最有经验的 C++,我会更深入地研究这些模式,但它们往往超出我的想象...... :(
  • 没问题。请注意,上面的代码和其他模式是不同的东西,这段代码不是关于抽象工厂的。
  • 是的,我知道,不过这很有趣,我从未见过有人超载operator()。我需要学习的东西太多了。
  • 嗯,希望此回复对您开始了解更多信息有所帮助。 :-)
【解决方案4】:

int integer = test&lt;int&gt;("int");
作品。

如果&lt;&gt; 类型,您不需要将“int”作为字符串传递
是 int 还是 float 可以通过函数中的代码检测到。

PS:“浮游者”?

【讨论】:

  • 哈哈,我需要一个更长的浮点名称,但什么都想不出来......添加 会给我一个警告:警告:从 'float' 转换为 'int'
【解决方案5】:

据我所知,不可能实现这样的功能来在字符串解析时返回不同的类型。 (我假设字符串是用户输入的结果)。 C++ 是强类型语言类型,因此编译器必须知道确切的返回类型。如果字符串值是硬编码的,您可以将实现更改为:

template<typename T>
T test()
{
    int   integer   = 42;
    float floateger = 42.42;

    if (std::is_same<T, int>::value)
        return integer;
    else
        return floateger;
}

int main()
{

    int integer = test<int>();

    cout << "INTEGER: " << integer << endl;
}

或者,如果您不限于 POD 类型,请查看 @molbdnilo 或 @skyking 的答案。

【讨论】:

    【解决方案6】:

    我会做这样的事情。与其返回值,不如将其作为第二个参数:

    template<class T>
    void test(const char *var_type, T& ret) {
        int integer = 42;
        float f = 42.42;
    
        if (0 == strcmp(var_type, "int")) {
            ret = integer;
        } else if (0 == strcmp(var_type, "float")) {
            ret = f;
        }
    }
    

    那么你可以这样称呼它:

    int integer = 0;
    float f = 0.0;
    test((const char *) "int", integer);
    printf("%d\n", integer);
    test((const char *) "float", f);
    printf("%f\n", f);
    

    【讨论】:

      【解决方案7】:

      借助 Boost,您可以使用 boost::variant: 来解决这个问题:

      typedef boost::variant< int, float, YourSpecialDataType > MixedData;
      

      然后让方法返回这个类型:

      MixedData test(std::string type) {
         int   integer   = 42;
         float floateger = 42.42;
      
         if (type == "int")
            return integer;
         if (type == "float")
            return floateger;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-04-09
        • 1970-01-01
        • 2017-08-18
        • 1970-01-01
        • 2015-04-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多