Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Partial specialization for pointer as function return type

I have a template wrapper function that returns a value like this:

template<class T>
T foo(Bar& bar, const char* key) {
    return bar.value<T>(key);
}

But I want it to handle pointer types a bit different, like this:

template<class T>
T foo(Bar& bar, const char* key) {
    return (T)bar.value<void*>(key);
}

So that I can do:

int x = foo<int>(bar, "x");
Baz* b = foo<Baz*>(bar, "b");

Writing it like above obviously gives me an error because of multiple definitions. Is there any other way to do this? I would prefer do not add a cast to each function that uses a pointer.

I've tried the following:

template<class T>
T foo(Bar& bar, const char* key) {
    if(std::is_pointer<T>::value)
        return (T)bar.value<void*>(key);
    else
        return bar.value<T>(key);
}

But that doesn't work either because there are QVariants involved and they produce an error by just instantiating one of its template functions with an unknown pointer type (the bar.value<T>).

like image 338
user408952 Avatar asked Dec 01 '22 00:12

user408952


2 Answers

Use tag dispatching to delegate the calls to helper functions that do different things based on whether T is a pointer type or not.

namespace detail
{
template<class T>
T foo(Bar& bar, const char* key, std::false_type /*not is_pointer*/) {
    return bar.value<T>(key);
}

template<class T>
T foo(Bar& bar, const char* key, std::true_type /*is_pointer*/) {
    return (T)bar.value<void*>(key);
}
}

template<class T>
T foo(Bar& bar, const char* key) {
    return detail::foo<T>(bar, key, std::is_pointer<T>{});
}
like image 60
Praetorian Avatar answered Dec 04 '22 13:12

Praetorian


Partial specialization for functions is not part of the language.

You could for example:

  1. Delegate to some class template. Class templates can be partially specialized.
  2. Use SFINAE.

    template<class T>
    typename std::enable_if<std::is_pointer<T>::value, T>::type
    foo(Bar& bar, const char* key) {return (T)bar.value<void*>(key);}
    
    template<class T>
    typename std::enable_if<!std::is_pointer<T>::value, T>::type
    foo(Bar& bar, const char* key) {return bar.value<T>(key);}
    
like image 21
Deduplicator Avatar answered Dec 04 '22 13:12

Deduplicator