5

假设以下代码段:

template <class T>
void fct(T* a, T* b){
  // do something
}

A a;
fct(&a, nullptr); // Problem here!

这很麻烦,因为调用参数是类型的A*nullptr_t因此编译器无法推断出模板参数T

一般来说,我可以想象几个如何解决这个问题的想法:

  • 定义A* b = nullptr和使用fct(&a, b)
  • fctnullptr案例定义一个带有一个参数的重载
  • 利用fct(&a, static_cast<A*>(nullptr))

或者有没有更干净的解决方案,比如创建一个类似“typed nullptr”的东西?

4

4 回答 4

6

只需将第二个参数设为非推断上下文,例如:

template <class T>
void fct(T* a, std::remove_reference<T*>::type b) {
于 2015-10-01T10:12:26.893 回答
2

我还建议以下解决方案:

template <class T, class U>
void fct(T* a, U b){
  T* b2 = b;
  // do something
}

A a;
fct(&a, nullptr); 

这允许更广泛地使用fct,但也许这正是您想要的。

例如,考虑

class A {};
class B : public A {};

...
A a;
B b;
fct(&a, &b); // calls fct<A>
// the following will not compile:
// fct(&b, &a);
于 2015-10-01T09:23:58.307 回答
1

您可以使用以下代码:

#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

}

此版本测试将允许f使用一个nullptr(但不能同时使用两者)或两个指向同一类型的指针进行调用。使用 c++14,您还可以使用std::conditional_t,std::remove_pointer_tstd::is_null_pointer删除一些 biolerplate 之类的东西。

于 2015-10-01T09:53:38.367 回答
0

正如问题已经说明的那样,nullptr实际上有一种类型:std::nullptr_t. 因此,只需为特定情况添加显式重载:

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

不需要为此提供一些模板参数class U

于 2015-10-01T10:19:40.533 回答