-2

i have a big problem.. I wonna select the Storage Service via a wrapper class. The returning value must be an object within the storage service class. I pasted my current approach. But my mindset didn't worked so far.

Error:

error: inconsistent deduction for auto return type: ‘SQL*’ and then ‘REDIS*’ return new REDIS();

The big wish is to have an interface class which defines the struct and some "driver classes" which contains all necessary operations for the target storage service.

I hope you have another approach, how I can solve this problem..

    #include <iostream>


class StorageTemplate {
    public:
        virtual bool UserhasSurName() = 0;
        virtual bool UserhasGivenName() = 0;
};

class SQL: public StorageTemplate {
    public:
        bool UserhasSurName() {
            //A SQL QUERY
            return true;
        }
        bool UserhasGivenName() {
            //AN ANOTHER SQL QUERY
            return true;
        }
};

class REDIS: public StorageTemplate {
    public:
        bool UserhasSurName() {
            //A REDIS CALL
            return false;
        }
        bool UserhasGivenName() {
            //A REDIS CALL
            return false;
        }
};


class controller {
    public:
        auto test(int select) {
            if( select == 1)
            {
                return new SQL(); 
            } else {
                return new REDIS();
            }
        }
};



int main(int argc, char const *argv[])
{
    controller cont;
    auto schnitzel = cont.test(1);
    auto mitzel = cont.test(2);
    std::cout << schnitzel->UserhasSurName() << std::endl;
    std::cout << mitzel->UserhasSurName() << std::endl;
}
N. Men
  • 3
  • 6

3 Answers3

1

The problem you are facing is the following: Consider your function

auto test(int select) {
    if (select == 1) {
        return new SQL(); 
    } else {
        return new REDIS();
    }
}

If you trying to evaluate test(1) this expands to

auto test(int select) {
    if (true) {
        return new SQL(); 
    } else {
        return new REDIS();
    }
}

which results in a type error!

I show you three workarounds for your problem:

1. Function template and if constexpr

Make test a function template and check for the correct type using the C++17 feature if constexpr:

template<typename T>
auto test() {
    if constexpr(std::is_same<T, SQL>::value) {
        return new SQL();
    } else {
        return new REDIS();
    }
}

Use it in main() like this:

int main(){
    controller cont;
    auto schnitzel = cont.test<SQL>();
    auto mitzel = cont.test<REDIS>();
    std::cout << schnitzel->UserhasSurName() << std::endl;
    std::cout << mitzel->UserhasSurName() << std::endl;
}

2. Function template and std::unique_ptr

If you want to avoid using the if constexpr you can simply return an instance of std::unique_ptr instead of a raw pointer. This is the preferred way to do:

template<typename T>
auto test() {
    return std::unique_ptr<T>(new T);
}

Alternatively you can just return std::make_unique<T>().

3. Returning an instance of the base class

This is is most obvious solution to avoid the type error: Just return an instance of the base class. As above a solution using smart pointers is preferred here:

std::unique_ptr<StorageTemplate> test(const int select) {
    if (select == 1) {
        return std::make_unique<SQL>();
    } else {
        return std::make_unique<REDIS>();
    }
}

If you really want to avoid using smart pointers just use raw ones like this:

StorageTemplate* test(const int select) {
    if (select == 1) {
        return new SQL();
    } else {
        return new REDIS();
    }
}
dtell
  • 2,488
  • 1
  • 14
  • 29
0

in this code

auto test(int select) {
    if( select == 1)
    {
        return new SQL(); 
    } else {
        return new REDIS();
    }

auto can't be deduced because it only match to exact type. so even if SQL and REDIS inherite from StorageTemplate, StorageTemplate won't be deduced. you need to spécifie the type

StorageTemplate* test(int select) {
    if( select == 1)
    {
        return new SQL(); 
    } else {
        return new REDIS();
    }
Tyker
  • 2,971
  • 9
  • 21
  • 1
    You should really use a smart pointer here, otherwise you have to remember in the call site to delete the pointer when done with it. – NathanOliver Jun 22 '18 at 13:35
  • @NathanOliver i fully agree but i tryed to change OP's code as little as possible – Tyker Jun 22 '18 at 13:36
  • Alternatively, he could static_cast each new object down to StorageTemplate*, but then what's the point of auto really.. – gct Jun 22 '18 at 13:37
  • Yes but OPs code has memory leak right there you should mention that in your answer – Slava Jun 22 '18 at 13:40
  • thanks!! Yeah i know smart pointers are better than raw c pointer. – N. Men Jun 22 '18 at 13:43
  • @N.Men this error isn't coming from the code you have shown – Tyker Jun 22 '18 at 13:52
  • @Slava on which location is a memory leak? – N. Men Jun 22 '18 at 13:52
  • @N.Men you test function allocate with new but thoses pointers are never deleted – Tyker Jun 22 '18 at 13:53
  • @N.Men memory leak is usually happens because of missing `delete`. Sorry I do not think it is theoretically possible to point exact location where `delete` is missing. – Slava Jun 22 '18 at 13:59
0

Error return Auto in test(),it's return two different types. Change by StorageTemplate*

class controller {
    public:
        StorageTemplate* test(int select) {
            if( select == 1)
            {
                return new SQL(); 
            } else {
                return new REDIS();
            }
        }
};
diegodfrf
  • 74
  • 2
  • 7