2015-10-01 30 views
5

の型をnullptr与える次のスニペットを仮定しますテンプレート控除

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

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

コールの引数の型A*nullptr_tのものであり、そのコンパイラはテンプレートパラメータTを推測することはできませんので、これは、トラブルになります。

  • fct(&a, static_cast<A*>(nullptr))
使用を A* b = nullptrを定義し、 nullptrケース
  • ためfct(&a, b)
  • fctのために一つの引数でオーバーロードを定義して使用します。

    一般的に、私はどのようにこれを解決するには、いくつかのアイデアを想像することができます

    もっと清潔な解決策がありますか、li "型付きnullptr"のようなものの作成

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

    これはfctの広い使い方が可能になりますが、多分それはあなたがしたいまさにそれだ:

  • +0

    希望する「型付きnullptr」は、「static_cast (nullptr)」と異なる場合がありますか? – Petr

    +2

    あなたの2番目の選択肢はベストベットのようです...オーバーロード(テンプレートの特殊化) – basav

    +0

    あなたはすでに質問に答えています... 1番目と3番目の選択肢は多かれ少なかれ同じです:T *とnullptrは必要ありません。 fct(&a、nullptr) '、2ndはそれを可能にするために明示的なオーバーロードを使います。私は別の答えを想像することはできません... –

    答えて

    2

    は、私はまた、次の解決方法をお勧めします。

    たとえば、次のコードを使用することができます

    class A {}; 
    class B : public A {}; 
    
    ... 
    A a; 
    B b; 
    fct(&a, &b); // calls fct<A> 
    // the following will not compile: 
    // fct(&b, &a); 
    
    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 
    
    } 
    

    このバージョンのテストは1 nullptr(両方ではない)でfを呼び出すことができます、または二つのポインタを持ちます同じ種類に。 C++ 14では、std::conditional_tstd::remove_pointer_tstd::is_null_pointerのようなものを使っていくつかのバイオプレートを取り除くこともできます。

    +0

    null以外の値に応じて、 'f 'または 'f 'を呼び出す必要があります。現在のバージョンは 'f(nullptr、&i)'として呼び出されると 'f 'を呼び出します。 – Petr

    +0

    @Petrこのコードにはさらに問題がありました。それらを修正しました。ありがとう! – Rostislav

    5

    ただ、第二引数非推測コンテキスト、例えばますstd::nullptr_t:質問は、すでに実際にnullptrが型を持っている、と述べたよう

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

    第2の関数引数の前に 'typename'がありませんか?より新しい、少し控えめな'std :: remove_reference_t'を使うこともできます。 – user1735003

    0

    。だから、特にそのような場合のために、明示的な過負荷を追加します。

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

    必要がありませんが、そのためのいくつかのテンプレート引数class Uを持っています。

    関連する問題