Give a nullptr type to output the template

Assume the following snippet:

template <class T> void fct(T* a, T* b){ // do something } A a; fct(&a, nullptr); // Problem here! 

This creates problems because the call arguments are of type A* and nullptr_t , so the compiler cannot output the template parameter T

As a rule, I can present some ideas on how to solve this:

  • Define A* b = nullptr and use fct(&a, b)
  • Define one argument overload for fct for nullptr case
  • Use fct(&a, static_cast<A*>(nullptr))

Or is there a cleaner solution, like creating something like "typed nullptr"?

+5
source share
4 answers

Just make the second argument a non-deducible context, for example:

 template <class T> void fct(T* a, std::remove_reference<T*>::type b) { 
+5
source

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 you to use fct more widely, but perhaps exactly what you want.

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); 
+2
source

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 } 

These version tests will allow f to be called 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.

+1
source

As already mentioned, nullptr actually of type: std::nullptr_t . So just add an explicit overload for the specific case:

 template <class T> void fct(T* a, std::nullptr_t b) { return fct<T>(a,static_cast<T*>(b)); } 

You do not need to have a class U template argument for this.

0
source

Source: https://habr.com/ru/post/1232689/


All Articles