2016-06-20 12 views
14

GCCとクラン異なる動作

struct Wrapper { 
    int value; 

    constexpr explicit Wrapper(int v) noexcept : value(v) {} 
    Wrapper(const Wrapper& that) noexcept : value(that.value) {} 
}; 

そして、この機能:

constexpr Wrapper makeWrapper(int v) 
{ 
    return Wrapper(v); 
} 

次のコードは、クラン(アップルLLVMのバージョン7.3.0)用にコンパイルに失敗し、しかし、両方-Wall -Wextra -Werror -pedantic-errorsで、GCC(4.9+)の罰金コンパイル:

constexpr auto x = makeWrapper(123); 

クランはと文句を言い"非constexprコンストラクタ 'Wrapper'は定数式では使用できません。"どのコンパイラが正しいのですか?

+0

現時点ではコンパイラはありません。コピーコンストラクタを削除するとどうなりますか? – ZaldronGG

+2

Repro clang3.7とgcc6.1、コピー可能なMCVE [here](http://coliru.stacked-crooked.com/a/d72a2d90f44bb0dc)、両方のコンパイラ用の修正プログラム[here](http://coliru.stacked- crooked.com/a/759e633b484f83a8)。 –

+0

@Baum mit Augenなぜ答えを投稿しませんか? –

答えて

14

WrappermakeWrapper()から返すときのコピーまたは移動は省略できますが、C++ 14が必要です。既存のコピーコンストラクタは非constexprであり、その存在は暗黙のムーブコンストラクタの作成を禁止します。その結果、clangは正しいと思います。コピーコンストラクタをconstexprにする必要があります。

C++では、コードが正しくなる可能性があることに注意してください。いくつかのコンテキストでは、コピー・エリジョンを必須とする提案があります。P0135r0。しかし、この変化はまだ作業用紙には載っていないようです。今週着陸するかもしれませんが(@ NicolBolasのおかげでそれはまだありません)私はmailingの更新された論文を見ていません。

+2

私はあなたがC++ ISO委員会(WG21)にいることを知っています、お願いしたい:*「いつ機能やコンストラクタは* ***アクセス可能です*? "* - コピー・エリジョンの要件の1つが"アクセス可能 "であるためです。 [this](http://eel.is/c++draft/class.copy#32)の段落を読んでください。 – WhiZTiM

+0

@WhiZTiM私はそれが関数またはコンストラクタが存在し、必要な署名を持っていると思います(私は使用しています"シグネチャ"は、 'constexpr'や他のものを含む関数に関するすべてのことを意味しますが、コンパイラは実際にそれを使用するかどうか自由に選択できます。しかし100%確かではありません。 –

+0

@WhiZTiM:_accessible_は、[暗黙的に]宣言されているメンバーを参照するだけで、削除されず、アクセス指定子に基づいて対応するコンテキストから呼び出すことができます。コンストラクタは存在する可能性がありますが、 'private'または' protected '呼び出しはクラス外からのものである。 11 [class.access]を指す12.8 [class.copy]パラグラフ30を見てください。引用したセクションは、copy/copy-elisionの部分のみを参照していることに注意してください。次の部分は 'constexpr'です。コピーコンストラクタはOKですが、' constexpr'ではありません。 –

4

Clangが正しいです。コピーコンストラクタ(RVO)を自動的に削除するので、g ++で動作します。 -fno-elide-constructorsを渡すとg ++はまた不平を言う。

C++ 14標準.. constexprオブジェクト内のコピーエリジオンについては明らかではない

[class.copy/32] ... (部分的にここに再現)

ときのエリジオンのための基準コピー/移動操作が満たされています.... ... が省略されていても、選択されたコンストラクタにアクセスできる必要があります。

accessibleの定義がわかるまでは? g ++も正しいと思いますか?オブジェクトの宣言に使用

dcl.constexpr/9

constexprの指定子は、CONSTとして オブジェクトを宣言する。そのようなオブジェクトはリテラルタイプを持ち、 を初期化するものとする。コンストラクタ呼び出しによって初期化された場合、その呼び出し は定数式([expr.const])になります。それ以外の場合、または constexpr指定子が参照宣言で使用されている場合、初期化子に表示される 完全表現はすべて、定数 の式になります。

Dietmar Kuhl's answerは、先を先取りしています。

デモ:

struct Wrapper { 
    int value; 

    constexpr explicit Wrapper(int v) noexcept : value(v) {} 
    Wrapper(const Wrapper& that) noexcept : value(that.value) {} 
}; 

constexpr Wrapper makeWrapper(int v) 
{ 
    return Wrapper(v); 
} 

int main() 
{ 
    constexpr auto x = makeWrapper(123); 
} 

コンパイル

g++ -std=c++14 -Wall -pedantic -fno-elide-constructors main.cpp && ./a.out 

live here

3

両方のコンパイラが正しいそれを参照してください。

constexpr関数と初期化プログラムのルールでは、constexpr以外の関数を呼び出せないとしています。

コピーエリジョンのルールでは、非constexprコピーコンストラクタが呼び出されるかどうかは不明です。

唯一の結論は、関数と初期化子がconstexprの要件を満たしているかどうかは不明です。そうであれば、コンパイラはそれを受け入れる必要があります。そうでない場合、コンパイラは問題を診断する必要があります。

関連する問題