10

完全に機能するコードの例を次に示します。


#include<iostream>
#include<vector>

template< class D, template< class D, class A > class C, class A = std::allocator< D > >
void foo( C< D, A > *bar, C< D, A > *bas ) {
  std::cout << "Ok!" << std::endl;
}

int main( ) {
  std::vector< int > *sample1 = nullptr;
  std::vector< int > *sample2 = nullptr;
  foo( sample1, sample2 );
  return( 0 );
}

ただし、以下のコードでは、コンパイラは std::vector< int >* を 2 番目のパラメーターの nullptr と一致させることができず、最初のパラメーターからテンプレートの型を推定することさえできません。


#include<iostream>
#include<vector>

template< class D, template< class D, class A > class C, class A = std::allocator< D > >
void foo( C< D, A > *bar, C< D, A > *bas ) {
  std::cout << "Ok!" << std::endl;
}

int main( ) {
  std::vector< int > *sample = nullptr;
  foo( sample, nullptr );
  return( 0 );
}

エラーメッセージは次のとおりです。


$ g++ -std=c++11 nullptr.cpp -o nullptr

nullptr.cpp: In function ‘int main()’:

nullptr.cpp:11:24: error: no matching function for call to ‘foo(std::vector<int>*&, std::nullptr_t)’

   foo( sample, nullptr );

nullptr.cpp:11:24: note: candidate is:

nullptr.cpp:5:6: note: template<class D, template<class D, class A> class C, class A> void foo(C<D, A>*, C<D, A>*)

 void foo( C< D, A > *bar, C< D, A > *bas ) {

nullptr.cpp:5:6: note:   template argument deduction/substitution failed:

nullptr.cpp:11:24: note:   mismatched types ‘C<D, A>*’ and ‘std::nullptr_t’

   foo( sample, nullptr );

なぜそれが起こるのですか?

4

5 に答える 5

7

C++ 標準から (4.10 ポインター変換 [conv.ptr])

1 null ポインター定数は、0 に評価される整数型の整数定数式 (5.19) prvalue、または型 std::nullptr_t の prvalue です。null ポインター定数はポインター型に変換できます。結果はその型の null ポインター値であり、オブジェクト ポインターまたは関数ポインター型の他のすべての値と区別できます。このような変換をヌルポインタ変換と呼びます。

最初の例では、2 つの nullptr はテンプレート引数の推定前に既に変換されています。したがって、同じタイプが 2 回あっても問題ありません。

2 番目のものには、一致しないastd::vector<int>と a and があります。std::nullptr_t自分で変換する必要があります: static_cast<std::vector<int>*>(nullptr).

于 2013-12-05T16:51:12.463 に答える
3

Compiler can not deduce the second argument type because std::nullptr_t is not a pointer type.

1 The pointer literal is the keyword nullptr. It is a prvalue of type std::nullptr_t. [Note: std::nullptr_t is a distinct type that is neither a pointer type nor a pointer to member type; rather, a prvalue of this type is a null pointer constant and can be converted to a null pointer value or null member pointer value. [§2.14.7]

于 2013-12-05T16:54:42.020 に答える
0

テンプレート引数推定はパターンマッチングです。基数への変換以外の引数の変換はあまり行いません (まあ、const型 and に修飾子を追加して参照しますdecay)。

nullptr変換できますがC< D, A >*、そのような型ではありません。そして、両方の引数が演繹に等しく参加します。

のようなものを使用して、2 番目の引数の推定をブロックできtypename std::identity<C< D, A > >::type*ます。最初の引数についても同じです。両方の引数に対して行うと、template型は推測されません。

もう 1 つの方法は、任意の 2 つの型を取得し、SFINAE を使用して、一方の型のポインターを他方の型に変換できること、および変換可能な型を他方の型から型に変換できることを確認することC<D,A>ですtemplate CDA。これはおそらく、関数型推論が何をすべきかについてのあなたの内部メンタル モデルと一致します。ただし、結果は非常に冗長になります。

さらに良いアプローチは、「これらの 2 つの引数で何をするつもりですか」と尋ね、型マッチングを行うのではなく、それに対してダック型テストを行うことです。

于 2013-12-05T19:34:37.487 に答える
-1

これは、引数として nullptr を持つテンプレートを作成できないようにするためです。あなたはおそらくそれを望んでいません。テンプレートで propper クラスを引数として使用し、nullptr をその引数の値として使用する必要があります。

次のいずれかを実行できます

  • テンプレートの適切なバージョンを明示的に呼び出す
  • テンプレートの適切な型に nullptr をキャストします。
  • 適切なポインター型のローカル変数を作成し、それに値 nullptr を与えて、その変数を使用して呼び出しを行います。
于 2013-12-05T16:47:50.157 に答える