3

いくつかの宣言が与えられた:

template <class T, T t>
struct foo {};

template <class T>
constexpr T ident(T t) {
   return t;
}

constexpr int bar() {
   return 0;
}

int main(int argc, const char *argv[])
{
    foo<bool, true> a;
    foo<int, bar()> b;
    foo<int, ident(0)> c;
    foo<int (*)(), bar> d;

    foo<int(*)(), ident(&bar)> e; // not accepted (gcc 4.7.2 crashes here, even)

    return 0;
}

余談ですが、興味深いことに、これによりgcc4.7.2でセグメンテーション違反が発生しました。エラーメッセージ(「外部リンケージを持つ関数のアドレスである必要があります」)を取得するために、4.8.0スナップショットのsvnビルドを実行する必要がありました...

最初はOKで、最後は許可されないのはなぜですか?このconstexprはcases広告のようなものではありませんか?コンパイラーは、他のタイプに対してそれを行うことができるので、どの関数ident(&bar)が話しているのかを完全に決定できるようです。

4

2 に答える 2

2

これはC++17以降で許可されます。N4198 (および最近C ++標準に投票された対応する文言用紙N4268 )を参照してください。Clangトランクはモードでコードを受け入れます-std=c++1z

于 2014-12-16T03:36:14.927 に答える
1

Eの問題は、関数へのポインタ型の非型テンプレートパラメータの場合、そのアドレスを取得することが有効でなければならないことです(14.3.2)。たとえば、foo<int(*)(), &ident(bar)>は無効です。したがって、の戻り値はident(bar)有効な外部リンケージを持つ関数へのポインタですが、型以外のテンプレートパラメータの場合、式全体は無効です。から0(またはnullptr)を返した場合ident(bar)は、コンパイルされます(14.3.2でも定義されています)。

この標準では、関数へのポインタのタイプで&を省略できますが、それでもそのアドレスを取得するには有効である必要があります。foo<int (*)(), bar>が有効であるため、これが機能する理由foo<int (*)(), &bar>です。他の関数呼び出しは、B、C(およびA)を整数定数に評価しますが、これは別のカテゴリに分類されます。

于 2013-04-07T19:49:46.037 に答える