I'd like to create a template that calls a member function on another object that returns the same type as the member function. The syntax for using decltype on the member function is a bit ugly, but it seems to work in every case except one.
Here's the call:
struct container: map<string, C>
{
template< typename MemFnPtrType, typename... _ArgTypes>
auto safeOperation(string key, MemFnPtrType mfp, _ArgTypes&&... args )
-> decltype( (((C*)nullptr)->*mfp)(args...))
{
C* pC = NULL;
decltype((pC->*mfp)(args...)) result;
iterator it = find(key);
if (it != end())
{
C* pC = &(it->second);
result = (pC->*mfp)(args...);
cout << "result:" << result << "\n";
}
else
{
cout << "key: " << key << " missing\n";
}
return result;
}
};
This works fine until the member function returns void.
Is there a way to detect this and leave out the offending lines?
I could obviously create a voidSafeOperation function. I don't mind creating another template, but I'd like to use the same name "safeOperation" so the call sites don't need to use different helpers based on the return type of the member function.
Thanks!
Full Example: http://cpp.sh/7ft
Unfortunately, I think you're stuck here with having to SFINAE on the return type. Start with a type trait (this is way cleaner than your decltype
expression)
template <typename MF, typename... Args>
using Res = typename std::result_of<MF(C, Args...)>::type;
And then just switch:
template <typename MF, typename... Args>
typename std::enable_if<
std::is_same<Res<MF, Args...>, void>::value
>::type safeOperation(string key, MF mfp, Args... args)
{
/* void case */
}
template <typename MF, typename... Args>
typename std::enable_if<
!std::is_same<Res<MF, Args...>, void>::value,
Res<MF, Args...>
>::type safeOperation(string key, MF mfp, Args... args)
{
/* non-void case */
}
Or you could tag dispatch on is_void
:
template <typename MF, typename... Args>
Res<MF, Args...> safeOperation(string key, MF mfp, Args... args)
{
return safeOperation(std::is_void<Res<MF, Args...>>{},
key, mfp, args...);
}
with:
template <typename MF, typename... Args>
void safeOperation(std::true_type /* void */,
string key, MF mfp, Args... args)
{ .. }
template <typename MF, typename... Args>
Res<MF, Args...> safeOperation(std::false_type /* non-void */,
string key, MF mfp, Args... args)
{ .. }
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