Recursive enable_if and type transform

I'd like to add same number pointers from typename U to typename T, for example when T = int*** and U = int*, the result is int****. So, I write the following:

#include <type_traits>

template <typename T, typename U,
          typename std::enable_if_t<std::is_pointer<U>::value>* = nullptr>
auto addPointer(T, U)
    -> decltype(addPointer(std::declval<std::add_pointer_t<T>>(),
                           std::declval<std::remove_pointer_t<U>>()));

template <typename T, typename U,
          typename std::enable_if_t<!std::is_pointer<U>::value>* = nullptr>
auto addPointer(T, U) -> T;

int main()
{
    using t =
        decltype(addPointer(std::declval<int***>(), std::declval<int*>()));
}

and I get the following on Linux clang 3.7:

$ clang++ -std=c++14 -stdlib=libc++ -lc++abi -Wall -Wextra a.cpp 
a.cpp:16:18: error: no matching function for call to 'addPointer'
        decltype(addPointer(std::declval<int***>(), std::declval<int*>()));
                 ^~~~~~~~~~
a.cpp:5:6: note: candidate template ignored: substitution failure [with T = int ***, U =
      int *, $2 = nullptr]: call to function 'addPointer' that is neither visible in the
      template definition nor found by argument-dependent lookup
auto addPointer(T, U)
     ^
/usr/bin/../include/c++/v1/type_traits:244:78: note: candidate template ignored: disabled
      by 'enable_if' [with T = int ***, U = int *]
  ...<bool _Bp, class _Tp = void> using enable_if_t = typename enable_if<_Bp, _Tp>::type;
                                                                         ^
1 error generated.

Why do I get the error?

Answers


As we're dealing with scalars, ADL will not look in the global namespace. Not only can the fallback overload not be found this way, the overload you're currently defining cannot be referred to in the trailing-return-type.

With C++14, there is a nicer solution to your problem, which circumvents that issue:

template <typename T>
T addPointer(T, ...);

template <typename T, typename U>
auto addPointer(T t, U* u) {return addPointer(&t, *u);}

Demo.


There is no need to use the whole SFINAE here, you can achieve this much more easily by simple template specialization:

template <typename T, typename U>
struct  addPointer
{
    typedef T type;
};

template <typename T, typename U>
struct addPointer<T,U*>
{
    typedef typename addPointer<T*,U>::type type;
};


int main()
{
    using t = addPointer<int***, int*>::type;
}

If you absolutely want to use enable_if and a function instead of a traits-struct, the following approach would work:

#include <type_traits>
template <typename T, typename U,
          typename K = std::enable_if_t<!std::is_pointer<U>::value>>
auto addPointer(T, U) -> T;

template <typename T, typename U,
          typename K = std::enable_if_t<std::is_pointer<U>::value>>
auto addPointer(T, U)
    -> decltype(addPointer(std::declval<std::add_pointer_t<T>>(),
                           std::declval<std::remove_pointer_t<U>>()));    
int main()
{
    using t =
        decltype(addPointer(std::declval<int***>(), std::declval<int*>()));
}

Need Your Help

HttpWebRequest cannot connect through proxy?

c# .net proxy httpwebrequest

I am trying to achieve something that should be simple according to everything I have read, but is just not working for me: send any request through a proxy.

Redis Queue use with django web app running on apache multi threads

django multithreading web redis

I was going through redis queue documentation at redis docs, but could not find info on how the queue handles en-queue calls from parallel threads of web server in the context of which it gets call...