Michael
Michael

Reputation: 712

C++ auto deduction of return type

I want to write a function that return different types based on different input as below.

enum MyType
{
    A,
    B
};

template<MyType T> struct MyStruct
{

};

static auto createMyStruct(MyType t)
{
    if(t==A)
        return MyStruct<A>();
    else
        return MyStruct<B>();
}

It didn't work out because there are two return types for one auto. Is there any other way to do this?

Upvotes: 0

Views: 251

Answers (3)

gomons
gomons

Reputation: 1976

I think you should learn abstract factory design pattern.

For use objects of type MyStruct<A> or MyStruct<B> you need common interface.

Common interface provided in abstract base class.

struct MyStruct
{
    virtual ~MyStruct() {}
    virtual void StructMethod() = 0;
};

struct MyStructA: public MyStruct
{
    void StructMethod() override {}
};

struct MyStructB: public MyStruct
{
    void StructMethod() override {}
};

std::unique_ptr<MyStruct> createMyStruct(MyType t)
{
    if (t==A)
        return std::make_unique<MyStructA>();
    else
        return std::make_unique<MyStructB>();
}

Upvotes: 0

vsoftco
vsoftco

Reputation: 56577

There is absolutely no way of having a (single) function that returns different types based on a runtime decision. The return type has to be known at compile time. However, you can use a template function, like this (thanks to @dyp for making me simplify the code):

#include <iostream>
#include <typeinfo>

enum MyType
{
    A,
    B
};

template<MyType>
struct MyStruct {};

template<MyType type>
MyStruct<type> createMyStruct()
{
    return {};
}

int main()
{
    auto structA = createMyStruct<A>();
    auto structB = createMyStruct<B>();

    std::cout << typeid(structA).name() << std::endl;
    std::cout << typeid(structB).name() << std::endl;
}

Upvotes: 1

jxh
jxh

Reputation: 70502

I am assuming you want to write code like this:

void foo (MyType t) {
    auto x = createMyStruct(t);
    //... do something with x
}

You are attempting to derive the right type for x at runtime. However, the return type of a function must be known at compile time, and the type resolution for auto is also determined at compile time.

You could instead restructure your code to be like this:

template<MyType T> struct MyStruct
{
    //...
    static void foo () {
        MyStruct x;
        //... do something with x
    }
};

The idea is to write a single foo() function whose only difference is the type of thing it is manipulating. This function is encapsulated within the type itself. You can now make a runtime decision if you have a mapping between MyType and MyStruct<MyType>::foo.

typedef std::map<MyType, void(*)()> MyMap;

template <MyType...> struct PopulateMyMap;

template <MyType T> struct PopulateMyMap<T> {
    void operator () (MyMap &m) {
        m[T] = MyStruct<T>::foo;
    }
};

template <MyType T, MyType... Rest> struct PopulateMyMap<T, Rest...> {
    void operator () (MyMap &m) {
        m[T] = MyStruct<T>::foo;
        PopulateMyMap<Rest...>()(m);
    }
};

template<MyType... Types> void populateMyMap (MyMap &m) {
    PopulateMyMap<Types...>()(m);
}

//...
    populateMyMap<A, B>(myMapInstance);

Then, to make a runtime decision:

void foo (MyType t) {
    myMapInstance.at(t)();
}

Upvotes: 0

Related Questions