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.
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
There is no need to return a const std::string
. You can just return a std::string
and the caller can decide if it wants it to be const or not. If you are okay with that, then your function would become
template<Options option>
static decltype(auto) func()
{
if constexpr (option == Options::optA)
{
return str;
}
else if constexpr (option == Options::optB)
{
return const_cast<const std::vector<std::string>&>(vec);
}
else //
{ // this bit is not really needed but I like
return; // being explicit that `void` is what we want to return
//
} //
}
and now decltype(auto)
will deduce for Options::optA
a std::string
, for Options::optB
a const std::vector<std::string>&
and for Options::optC
, void
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With