23

次のコードはclang(libc ++)でコンパイルされ、gcc(libstdc ++)で失敗します。gcc(libstdc ++)が初期化子リストについて文句を言うのはなぜですか?return引数は統一された初期化構文を使用していると思いました。

std::tuple<double,double> dummy() {
  return {2.0, 3.0};
}

int main() {   
  std::tuple<double,double> a = dummy();   
  return 0;
}

エラー:22行目:初期化子\リストから'std :: tuple'に変換すると、明示的なコンストラクター' constexpr std :: tuple <_T1、_T2> :: tuple(_U1&\&、_U2 &&)[with _U1 = double; _U2=ダブル; =無効; _T \1=ダブル; _T2 = double] '

注: GCC(libstdc ++)(およびclang(libc ++))は受け入れます

std::tuple<double,double> dummy {1.0, 2.0};

同じではないですか?

更新:これはlibc++拡張機能です。http ://llvm.org/bugs/show_bug.cgi?id = 15299を参照し、以下のHowardHinnantによる回答も参照してください。

4

2 に答える 2

34

for とは異なり、残念ながらpair<>a の暗黙的な構築はできません。tuple<>使用する必要がありますmake_tuple()

#include <tuple>

std::tuple<double,double> dummy()
{
    return std::make_tuple(2.0, 3.0); // OK
}

int main() 
{   
    std::tuple<double,double> a = dummy();   
    return 0;
}

std::tupleには可変引数コンストラクタがありますが、 としてマークされていexplicitます。したがって、テンポラリが暗黙的に構築可能でなければならないこの状況では使用できません。C++11 標準のパラグラフ 20.4.2 によると:

namespace std {
    template <class... Types>
    class tuple {
    public:

        [...]
        explicit tuple(const Types&...); // Marked as explicit!

        template <class... UTypes>
        explicit tuple(UTypes&&...);     // Marked as explicit!

同じ理由で、タプルの初期化にコピー初期化構文を使用することは違法です。

std::tuple<double, double> a = {1.0, 2.0}; // ERROR!
std::tuple<double, double> a{1.0, 2.0}; // OK

または、タプルを引数として関数に渡すときに暗黙的にタプルを作成するには:

void f(std::tuple<double, double> t) { ... }
...
f({1.0, 2.0}); // ERROR!
f(make_tuple(1.0, 2.0)); // OK

したがって、 でstd::tuple返すときに明示的に構築するdummy()と、コンパイル エラーは発生しません。

#include <tuple>

std::tuple<double,double> dummy()
{
    return std::tuple<double, double>{2.0, 3.0}; // OK
}

int main() 
{   
    std::tuple<double,double> a = dummy();   
    return 0;
}
于 2013-02-19T16:02:04.123 に答える
24

Andy Prowl の答えは正しいです。libc++ の実装についてコメントしたかったのですが、コメント形式では十分なスペースや形式の選択肢がありません。

Daniel Krügler と私は約 1 年前にこの件について話し合い、この問題は libc++ に拡張機能を追加して現場での経験を積む価値があると確信させてくれました。そしてこれまでのところ、フィードバックは肯定的です。ただし、明確にしたいのですが、これはexplicitctor から削除するほど簡単ではありませんexplicit constexpr tuple(UTypes&&...)

ダニエルの計画は、tuple各要素の暗黙的/明示的な構築を完全に尊重するコンストラクターを提供することです。またすべての要素が初期化子リストのすべての引数から暗黙的に構築される場合、タプルの構築は暗黙的であり、それ以外の場合は明示的になります。

例えば:

与えられた:

#include <tuple>

struct A
{
};

struct B
{
    B() = default;
    B(A);
};

struct C
{
    C() = default;
    explicit C(A);
};

それで:

std::tuple<>
test0()
{
    return {};  // ok
}

それについては何も言うことはありません。しかし、これも問題ありません:

std::tuple<B>
test1B()
{
    return {A()};  // ok B(A) implicit
}

からAへの変換Bは暗黙的であるためです。ただし、次はコンパイル時エラーです。

std::tuple<C>
test1C()
{
    return {A()};  // error, C(A) is explicit
}

からAへの変換Cは明示的であるためです。このロジックは、複数要素のタプルにも適用されます。暗黙的な変換を行うには、すべての要素に引数リストからの暗黙的な変換が必要です。

std::tuple<A, B>
test2B()
{
    return {A(), A()};  // ok each element has implicit ctor
}

std::tuple<A, C>
test2C()
{
    return {A(), A()};  // error, C(A) is explicit
}

強調しておきますが、これは現時点では libc++ の拡張機能です。

アップデート

チコは、この回答を更新することを提案しました。

この回答が与えられたので、Daniel Krügler は論文を書き、この 4 月にブリストルの C++ 委員会に提出しました。この論文は好評でしたが、現在の作業草案に投票するには週の後半にレビューされました。

アップデート

Daniel の提案は現在、現在の作業草案の一部です。libc++ の実装は、この点で次の C++ 標準 (C++17 を希望) の標準になるように設定されています。

于 2013-02-19T16:54:36.917 に答える