2
#include <iostream>
#include <string>
#include <initializer_list>

class A
{
 public:
  A(int, bool) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
  A(int, double) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
  A(std::initializer_list<int>) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};

int main()
{
  A a1 = {1, 1.0};
  return 0;
}

(この質問はこれのフォローアップです。)

上記のプログラムはコンパイルに失敗しますclang35 -std=c++11

init.cpp:15:14: error: type 'double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing]
  A a1 = {1, 1.0};
             ^~~
init.cpp:15:14: note: insert an explicit cast to silence this issue
  A a1 = {1, 1.0};
             ^~~
             static_cast<int>( )

while をg++48 -std=c++11選択すると、不適切な形式の狭小化を診断するための警告が生成されます

init.cpp: In function ‘int main()’:
init.cpp:15:17: warning: narrowing conversion of ‘1.0e+0’ from ‘double’ to ‘int’ inside { } [-Wnarrowing]
   A a1 = {1, 1.0};
                 ^
init.cpp:15:17: warning: narrowing conversion of ‘1.0e+0’ from ‘double’ to ‘int’ inside { } [-Wnarrowing]

結果を生成します

A::A(std::initializer_list<int>)

私の質問はA::A(std::initializer_list<int>)、実行可能な過負荷にする必要があるかどうかです。initializer_list以下は、過負荷が実行可能であってはならないことを暗示していると思われる標準的な引用です。

から13.3.2 [over.match.viable]

第 2 にF、実行可能な関数であるためには、各引数に対して、その引数を の対応するパラメーターに変換する暗黙の変換シーケンスが存在する必要がありますF

から4 [conv]

宣言が次の場合にのみ、式を暗黙的に型に変換できeます。いくつかの発明された一時変数の場合、整形式です。TT t=et

から8.5.1 [dcl.init.aggr]

initializer-clauseが式であり、式を変換するために縮小変換が必要な場合、プログラムは不適切な形式です。

以下は整形式ではないため、8.5.1andを使用します。4

std::initializer_list<int> e = {1, 1.0};

{1, 1.0}は に暗黙的に変換できませんstd::initializer_list<int>

からの引用を使用すると、 のオーバーロード解決を行うときに実行可能な関数13.3.2ではないことを意味するべきではありませんか? 実行可能なコンストラクターが見つからない場合、このステートメントは を選択すべきではありませんか?A::A(std::initializer_list<int>)A a1 = {1, 1.0};initializer_listA::A(int, double)

4

1 に答える 1

4

あなたの分析における問題は、その声明が

int t = 1.0;

は確かに整形式です - からdoubleへの暗黙の変換がint明らかに存在します。[over.ics.list]/4 にも説明があります。

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

初期化子リストのすべての要素は、暗黙的に に変換できるintため、コンストラクターは実行可能であり、選択されます。ただし、それが選択されると、全体がハードエラーになります [dcl.init.list]/(3.6):

適用可能なコンストラクターが列挙され、オーバーロード解決 (13.3、13.3.1.7) によって最適なコンストラクターが選択されます。引数のいずれかを変換するために縮小変換 (以下を参照) が必要な場合、プログラムは不適切な形式です。

ご覧のとおり、呼び出すコンストラクターは、ナローイング チェックが実行される前に決定されます。つまり、イニシャライザ リスト コンストラクタの実行可能性は、引数の縮小に依存しません。
したがって、コードは不適切な形式である必要があります。

目的の動作を実現する 1 つの方法は、SFINAE でコンストラクター テンプレートを使用することです。

template <typename T, typename=std::enable_if_t<std::is_same<int, T>{}>>
A(std::initializer_list<T>) { std::cout << __PRETTY_FUNCTION__ << std::endl; }

デモ

于 2015-01-21T18:35:11.540 に答える