Reputation: 7809
Suppose the following snippet:
template <class T>
void fct(T* a, T* b){
// do something
}
A a;
fct(&a, nullptr); // Problem here!
This makes trouble, since the call arguments are of type A*
and nullptr_t
and so the compiler can not deduce template parameter T
.
Generally, I can imagine several ideas how to solve this:
A* b = nullptr
and use fct(&a, b)
fct
for the nullptr
casefct(&a, static_cast<A*>(nullptr))
Or is there a more clean solution, like the creation of a something like a "typed nullptr"?
Upvotes: 5
Views: 1683
Reputation: 3977
You can use the following code:
#include <type_traits>
template<class T>
void f_impl(T*, T*)
{
std::cout << typeid(T).name() << "\n";
}
template<class T, class U>
void f(T l, U r)
{
static_assert((std::is_same<T, U>::value && std::is_pointer<T>::value) ||
(std::is_same<T, std::nullptr_t>::value && std::is_pointer<U>::value) || // First non-null
(std::is_same<U, std::nullptr_t>::value && std::is_pointer<T>::value) // Second non-null
, "");
using P = typename std::conditional<std::is_same<T, std::nullptr_t>::value, U, T>::type;
f_impl<typename std::remove_pointer<P>::type>(l, r);
}
int main()
{
int i;
f(&i, nullptr);
f(nullptr, &i);
// f(i, nullptr); // won't compile - non-pointer
f(&i, &i);
double d;
// f(&i, &d); // - won't compile
}
This version tests will allow to call f
with one nullptr
(but not both), or with two pointers to the same type. With c++14 you can also use things like std::conditional_t
, std::remove_pointer_t
and std::is_null_pointer
to remove some biolerplate.
Upvotes: 1
Reputation: 179819
As the question already states, nullptr
in fact has a type: std::nullptr_t
. So just add an explicit overload for specifically that case:
template <class T>
void fct(T* a, std::nullptr_t b) { return fct<T>(a,static_cast<T*>(b)); }
No need to have some template argument class U
for that.
Upvotes: 0
Reputation: 179819
Just make the second argument a non-deduced context, e.g:
template <class T>
void fct(T* a, std::remove_reference<T*>::type b) {
Upvotes: 7
Reputation: 9997
I would also suggest the following solution:
template <class T, class U>
void fct(T* a, U b){
T* b2 = b;
// do something
}
A a;
fct(&a, nullptr);
This allows for a wider usage of fct
, but maybe that's exactly what you want to.
For example, consider
class A {};
class B : public A {};
...
A a;
B b;
fct(&a, &b); // calls fct<A>
// the following will not compile:
// fct(&b, &a);
Upvotes: 2