3

子メソッド内でクラスの可変個引数テンプレート型リストを次のように拡張しようとしています:

template<typename... P>
struct Foo
{
    template<P...> // error C3522: 'P' : parameter
                   // pack cannot be expanded in this context
    static void Bar(P... a){}
};

このコードの何が問題なのですか?それとも単に MSVS '12: Nov. '12 CTP のバグですか?

(はい、この例の明示的なテンプレートの特殊化が冗長であることはわかっています。)

上記は、エラーを再現できる最も単純なケースです。完全なコードは次のとおりです。

template<typename FuncSignature>
class Callback;

template<typename R, typename... P>
class Callback<R (P...)>
{
public:

    Callback()                    : func(0), obj(0) {}

    Callback& operator=(const Callback& rhs)
    { obj = rhs.obj; func = rhs.func; return *this; }

private:
    typedef R (*FuncType)(const void*, P...);
    Callback(FuncType f, const void* o) : func(f), obj(o) {}

private:
    FuncType func;
    const void* obj;

    template<typename FR, typename... FP>
    friend class FreeCallbackFactory;
};

template<typename R, typename... P>
class FreeCallbackFactory
{
private:
    template<R (*Func)(P...)>
    static R Wrapper(const void*, P... a)
    {
        return (*Func)(a...);
    }

public:
    template<R (*Func)(P...)>
    inline static Callback<R (P...)> Bind()
    {
        return Callback<R (P...)>
            (&FreeCallbackFactory::Wrapper<Func>, 0);
    }
};
template<typename R, typename... P>
inline FreeCallbackFactory<R, P...>
    GetCallbackFactory(R (*)(P...))
{
    return FreeCallbackFactory<R, P...>();
}

void Test(){}

int main(int argc, char** argv){
Callback<void ()> cb = GetCallbackFactory(&Test).Bind<&Test>()
}

g ++で正常にコンパイルされるため、コンパイラのバグのみを想定しており、継続的な調査結果はまだこれを指しているだけです.1つずつ明示的に展開する以外に、これに対する回避策はありますか?


編集: これはコンパイラ チームにバグとして報告されており、パッチはコンパイラの次のリリースに含まれる予定です。[リンク]

4

2 に答える 2

1

コードは正しいように見えますが、意図したとおりに実行されているとは思えません。宣言

template <P...>
static void Bar(P... a);

P...テンプレート引数および関数引数として値を取る関数を宣言します。つまり、 の要素はP型以外のパラメーター (整数、ポインター、または参照など) を許可する型である必要があり、関数を呼び出すときにそれぞれの値をテンプレート パラメーターとして提供する必要があります。このような関数の呼び出しは、次のようになります (ただし、gcc も clang もテンプレート パラメーターを渡す必要はないようです)。

Foo<int, int>::Bar<1, 2>(3, 4);

そうは言っても、gcc と clang の両方によって生成されたエラー メッセージに基づいて、メンバー関数テンプレートの特殊化を作成することはできないようですが、標準でこれを確認していません。おそらく、テンプレート宣言を省略して使用する必要があると思います

static void Bar(P... a);
于 2012-12-02T23:04:15.120 に答える
0

私には、コードが正しく見えません。パック展開 P... は、一連の型に展開されます。正しいことを達成する目的に応じて、template<P...>パーツを削除することになります。この場合、各クラス テンプレート インスタンスには、クラスと同じパラメーターを持つ 1 つの Bar() メソッドがあります。もう 1 つは、これが関連のないパラメーター パックであるということです。この場合、無制限のメソッド セットが生成されます。その場合、メソッドを次のように宣言する必要があります。

template<typename... U> static void Bar(U...);

名前 P を再利用することはあまり役に立たないと思います。

于 2013-02-27T21:00:38.887 に答える