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>();
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 optB
– const std::vector<std::string>&
, and void
otherwise.
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);
}