c++return-type-deduction

specialize return type to void or const lvalue reference


I'm trying to accomplish the below..

enum class Options : uint8_t {    
    optA,
    optB,
    optC
};

class Test {
public:

    static std::string str;
    static std::vector<std::string> vec;

    template<Options option>
    static auto func()
    {
        if constexpr (option == Options::optA)
        {
            return str; // want this to deduce to 'const std::string', but only does so if 'const auto' (const std::string& also fine though)
        }
        else if constexpr (option == Options::optB)
        {
            return vec; // want this to deduce to 'const std::vector<std::string>&' but only does so if 'const auto&'
        }

        // want this to deduce to 'void' but only can if 'auto'
    }
}

But of course it doesn't work for the commented reasons.

I know I could...

1) specialize the function outside of the class body for each option, and deliberately specify the return type

or 2) explicitly pass in the return type when calling the function

But is there any cleaner solution where all I need to do is pass in the single Options value into the template and the rest gets derived inside of a single function body?

const std::string& value = Test::func<Options::optA>();
const std::vector<std::string>& values = Test::func<Options::optB>();
Test::func<Options::optC>();

Solution

  • For a non-static func(), you can mark it as const and use decltype(auto) deduction:

    template<Options option>
    decltype(auto) func() const
    {
        if constexpr (option == Options::optA)
            return (str);
        else if constexpr (option == Options::optB)
            return (vec);
    }
    

    str and vec are parenthesized so that decltype(auto) deduce a reference type. For optA it will return const std::string&, for optBconst std::vector<std::string>&, and void otherwise.

    Demo 1


    For a static member function and static members you can write:

    template<Options option>
    static decltype(auto) func()
    {
        if constexpr (option == Options::optA)
            return std::as_const(str);
        else if constexpr (option == Options::optB)
            return std::as_const(vec);
    }
    

    Demo 2