3

次のコードを検討してください。整数と整数のベクトルで構成されるタプルは、マップのキーとして定義されます。ただし、キーとして整数と整数で構成されるタプルを挿入または検索するときに、コンパイラーがエラーをスローしないことに驚きました。タプルの2番目の要素は整数の型ベクトルである必要があるため、これはどのようになり ますか?

std::map <boost::tuple<int, vector<int > >, int> test;
std::map <boost::tuple<int, vector<int > >, int>::iterator test_it;

vector <int> t;
t.push_back(4);

test.insert(make_pair(boost::make_tuple(3, t), 4));

test.insert(make_pair(boost::make_tuple(3, 6), 4));

test_it = test.find(boost::make_tuple(3, 7)); 
if(test_it != test.end()) 
throw " test is passed";  
4

2 に答える 2

1

Boostおよび多くのC++標準ライブラリ実装のバグのようです。pair問題はとの両方で共有されtupleます。それを示す最も簡単なコードは次のとおりです。

#include <vector>
#include <utility>
using namespace std;
int main() {
    //compiles
    pair<int,vector<int>> bug1( pair<int,int>(5,6) );

    //compiles
    pair<int,vector<int>> bug2;
    bug2 = pair<int,int>(5,6);
}

Clang 4.0とlibc++他の1つはこれを受け入れ、ComeauOnlineもそれを受け入れます。GCC4.7.1でエラーが発生します。

次のように、コンパイルしてはいけません。

20.3.2 / 12

template<class U, class V> pair(const pair<U, V>& p);

備考:const U&が暗黙的にfirst_typeに変換可能であり、const V&が暗黙的にsecond_typeに変換可能でない限り、このコンストラクターはオーバーロード解決に参加しません。

20.3.2 / 23

template<class U, class V> pair& operator=(const pair<U, V>& p);

必要なもの:is_assignable<first_type&, const U&>::valueistrueおよびis_assignable<second_type&, const V&>::valueis true

于 2012-08-31T12:22:44.963 に答える
1

問題は暗黙の変換です。intからで はありませんstd::vector<int>; そこに含まれるコンストラクターが宣言されているexplicitため、これは機能しません。したがって、暗黙の変換には使用できません。暗黙の変換はfromstd::pair<int, int>から std::pair<int, std::vector<int> >。です。これは、テンプレートから派生したコンストラクターを使用しますtemplate <typename U1, typename U2> std::pair( std::pair<U1, U2> const& )。これは暗黙的ではありません。そして、このコンストラクターの定義は次のとおりです。

template <typename T1, typename T2>
template <typename U1, typename U2>
std::pair<T1, T2>::std::pair( std::pair<U1, U2> const& other )
    : first( other.first )
    , second( other.second )
{
}

(これは、標準で指定されている方法とは異なります。ただし、C ++ 03の仕様では、他の多くのことは許可されていません。C++ 11では、可​​能な場合に移動して構築できるように、余分な荷物がたくさんありますが、私は最終的な効果は同じだと思います。)

このコンストラクターでは、暗黙的な変換ではなく、コンストラクターの明示的な呼び出しがあることに注意してください。したがって、の暗黙的な変換がpair機能するには、2つのタイプが明示的に変換可能であるだけで十分です。

個人的には、これが本来の意図ではなかったと思います。実際、言語に追加される前に周囲の言語のほとんどstd::pairが凍結explicitされていたのではないかと思うので、問題はありませんでした。その後、誰もこの問題を再検討することを考えませんでした。また、C ++ 11では、再検討すると下位互換性が失われます。したがって、予期しない変換が発生します。

転送によって明示的な変換が暗黙的になるのは、これだけではないことに注意してください。検討:

std::vector<std::vector<int> > v2D( 5, 10 );

明らかに、で10はありませんstd::vector<int>(これは、2番目の引数がどうあるべきかです)。しかし...C++ 03では、これはコンストラクターテンプレートと一致します。

template<typename ForwardIterator, typename ForwardIterator>
std::vector( ForwardIterator begin, ForwardIterator end );

そして、標準にはこれのためのいくつかの特別な言語があります:

—コンストラクター

template <class InputIterator>
X(InputIterator f, InputIterator l, const Allocator& a = Allocator())

次と同じ効果があります:

X(static_cast<typename X::size_type>(f),
static_cast<typename X::value_type>(l), a)

InputIteratorが整数型の場合。

そして、暗黙の変換は明示的になりました。

(この特別な言語がないと、

std::vector<int> v(10, 42);

コンパイルに失敗します:上記のテンプレートコンストラクターのインスタンス化は完全一致であり、。よりも優れていstd::vector<int>( size_t, int )ます。委員会は、上記の最初の整数の明示的なキャストを要求することsize_tは、おそらくあまりにも多くのユーザーに質問していると感じました。)

C ++ 11は、ここでの表現を大幅に変更しました。

std::vector<int, std::vector<int>> v2D( 10, 42 );

もはや合法ではありません。

少なくとも私が見ることができるような変更は、のコンストラクターには適用されませんでしたstd::pair

于 2012-08-31T14:00:18.447 に答える