9

この質問に答えるとき、gcc (コンパイルされたコード) と clang (コードが拒否された)で次のコードを試しました。

typedef long (*func)(int);

long function(int) { return 42; }

struct Test
{
    static constexpr func f = &function;
};

template<func c>
struct Call
{
    static void f()
    {
        c(0);
    }
};

int main()
{
    Call<Test::f>::f();
}

constexpr の初期化は問題ないと思いますが、どのコンパイラが正しいかはわかりませんTest::f。エラーclang出力は次のとおりです。

error: non-type template argument for template parameter of pointer type 'func'
       (aka 'long (*)(int)') must have its address taken
  1. どのコンパイラが正しいですか?
  2. clang が正しい場合、その理由と、このエラーの本当の意味は何ですか?

編集:「理由」については、DyPの質問を参照してください。

4

1 に答える 1

9

14.3.2 テンプレートの非型引数 [temp.arg.nontype]

非型、非テンプレートのテンプレート パラメータのテンプレート引数は、次のいずれかになります。

[...]

— 静的記憶域 > 期間および外部リンケージまたは内部リンケージを持つオブジェクトのアドレスを指定する定数式 (5.19)、または外部リンケージまたは内部リンケージを持つ関数 (関数テンプレートおよび関数テンプレート ID を含むが、非静的クラス メンバーを除く) が表現される(括弧を無視して) & id-expressionと同じですが、名前が関数または配列を参照する場合は & を省略でき、対応するテンプレート パラメーターが参照の場合は省略されます。[...]

(n3485、地雷強調)

制限されている理由は正確にはわかりませんが、コンパイル時に関数アドレスが利用できないという事実に関連している可能性があります (テンプレートのインスタンス化目的の代わりになる可能性があります)。


編集:Synxisのフォローアップの質問(コメント)による回答の強化

constexpr func = &function;

^ これは整形式です。関数のアドレスを使用してconstexprオブジェクトを初期化できます。問題は、ポインタを次の形式以外の非型テンプレート引数として使用することが明示的に禁止されていること&identifierです。

using My_Call     = Call < &function >;  // fine

constexpr func mypointer = &function;    // fine
using My_Ind_Call = Call < func >;       // forbidden, argument not of form `&id`
于 2013-04-07T20:37:07.920 に答える