7
#include <iostream>
#include <string>
#include <typeinfo>
#include <typeindex>
#include <map>
#include <vector>

class Base{
public:
    virtual ~Base() {}

};

class Derived: public Base { };

int main(){

    int arr[10];
    Derived d;
    Base *p = &d;

    std::map<std::type_index, std::string> proper_name = {
        {typeid(int), "int"}, {typeid(double), "double"}, {typeid(float), "float"}, {typeid(char), "char"},
        {typeid(Base), "Base"}, {typeid(Derived), "Derived"}, {typeid(std::string), "String"},
        {typeid(int[10]), "Ten int Array"}, {typeid(p), "Base Pointer"}};

}

このリストの初期化で発生する暗黙の変換を理解しようとしています。13.3.1.7N3337から:

非集約クラス型 T のオブジェクトがリスト初期化される (8.5.4) 場合、オーバーロードの解決は 2 つのフェーズでコンストラクターを選択します。

  1. 最初は、候補関数はクラス T の初期化子リスト コンストラクター (8.5.4) であり、引数リストは単一の引数としての初期化子リストで構成されます。

  2. 実行可能な初期化子リスト コンストラクターが見つからない場合、オーバーロードの解決が再度実行されます。ここで、候補関数はすべてクラス T のコンストラクターであり、引数リストは初期化子リストの要素で構成されます。

8.5.4:

コンストラクターは、その最初のパラメーターが型であるか、ある type に対してstd::initializer_list<E>cv 修飾されている可能性のある参照であり、他のパラメーターがないか、他のすべてのパラメーターがデフォルト引数を持っている場合、初期化子リスト コンストラクターです。std::initializer_list<E>E

したがって、次のコンストラクタのリストは次のことをstd::map示しています

map (initializer_list<value_type> il, const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type());

は候補関数でvalue_type、この場合はpair<const type_index, std::string>です。最後に から13.3.3.1.5:

パラメーターの型がstd::initializer_list<X>or の「配列X」135 であり、初期化子リストのすべての要素を暗黙的に に変換できる場合X、暗黙的な変換シーケンスは、リストの要素を に変換するために必要な最悪の変換Xです。

したがって、波括弧リストの要素が暗黙的に に変換される限り、これは有効な変換ですpair<const type_index, std::string>。しかし、それらの要素は波括弧リストそのものでもあります。Pairはイニシャライザ リスト コンストラクタを取りません。ここから、ブレース付き初期化リストからのコピー初期化は13.3.1.7、オブジェクトを構築するために の 2 番目の部分を使用するようです。したがって、次のようになります。

pair<const type_index, std::string> p = {typeid(int), "int"}

になります:

pair<const type_index, std::string> p(typeid(int), "int")

しかし、これは暗黙の変換と見なされますか? 2引数のコンストラクターの使用を暗黙の変換と見なすにはどうすればよいですか? これに関する規格のコメントは何ですか?

4

1 に答える 1

3

あなたの結論は

pair<const type_index, std::string> p = {typeid(int), "int"};

になる

pair<const type_index, std::string> p(typeid(int), "int");

最初のステートメントはcopy-list-initializationであり、2 番目のステートメントはdirect-initializationであるため、正確ではありません。コンストラクターが選択された場合、copy-list-initialization の形式が正しくないことを除いて、この 2 つは同一ですexplicit(前者では縮小変換は許可されません)。

したがってpair、問題のコンストラクターが次のように定義されている場合

template<class U1, class U2>
explicit constexpr pair(U1&& x, U2&& y);

direct-initializationは引き続き成功しますが、copy-list-initializationは失敗します。[over.match.list]の引用した部分のすぐ下から引用

copy-list-initialization では、explicitコンストラクターが選択されている場合、初期化の形式が正しくありません。


それ以外は、あなたの言っていることはすべて正しいです。コンストラクターはそうではないため、pairコンストラクターは暗黙的な変換であり、初期化リスト コンストラクターがないため、 [over.match.list]explicitの 2 番目の箇条書きに従ってオーバーロード解決の対象と見なされます。pair

于 2016-01-20T23:24:06.447 に答える