3

次のコード スニペットは、私が達成したいことを示しています。つまり、2 つのテンプレートの特殊化 (ここではメイン テンプレートと特殊化です) を作成します。1 つは非 const メンバー関数に使用され、もう 1 つは const メンバー関数に使用されます。

// instantiate for non-const member functions
template <typename C, void(C::*F)()>
struct A {};

// instantiate for const member functions
template <typename C, void(C::*F)() const>
struct A<C const, F> {};

struct foo
{
    void bar() const {}
    typedef A<foo const, &foo::bar> bar_type;

    void baz() {}
    typedef A<foo, &foo::baz> baz_type;
};

このコードは、gcc 4.7、Intel 13.0、および MSVC 2012 を使用すると正常にコンパイルされますが、Clang 3.3 または Comeau 4.3.10.1 を使用するとコンパイルに失敗します。私はClangが実際に正しいと信じています。

このコードを書き直して、標準に準拠させる (つまり、Clang でコンパイルする) にはどうすればよいですか?

コンパイルエラーは次のとおりです。

test_6.cpp:22:26: error: non-type template argument of type 'void (foo::*)() const' cannot be converted to a value of type 'void (const foo::*)()'
    typedef A<foo const, &foo::bar> bar_type;
                         ^~~~~~~~~
test_6.cpp:7:33: note: template parameter is declared here
template <typename C, void (C::*F)()>
                                ^
4

3 に答える 3

3

メンバー関数タイプをテンプレートパラメーターにすると、さまざまなメンバー関数タイプにテンプレートを特化できます。

template <typename C, typename F, F>
struct A;  // undefined

template <typename C, void(C::*f)()>
struct A<C, void(C::*)(), f> {};

template <typename C, void(C::*f)() const>
struct A<C const, void(C::*)() const, f> {};

struct foo
{
    void bar() const {}
    typedef A<foo const, decltype(&foo::bar), &foo::bar> bar_type;

    void baz() {}
    typedef A<foo, decltype(&foo::baz), &foo::baz> baz_type;
};
于 2013-03-04T00:46:20.567 に答える
3

それは(部分的な)専門化がどのように機能するかではありません。特殊化で引数を指定する場合、対応するパラメーターの種類と一致する必要があります。

プライマリ テンプレートには、非 constメンバ関数へのポインタ(PTNCMF) パラメータがあり、その種類のテンプレート引数が必要です。ただし、部分的な特殊化ではconstメンバ関数へのポインタ(PTCMF) が引数として渡されるため、不一致が生じます。PTCMF は PTNCMF に変換できないため、部分的な特殊化は無効です。

問題については以上で、解決策に移ります。引数の型を実際の引数から分離する必要があります。1 つの方法は次のとおりです。単純に、constクラス タイプが PTCMF とのみ一致することをアサートします。

#include <type_traits>

template<class Fty>
struct is_ptcmf : std::false_type{};

template<class C, class R, class... Args>
struct is_ptcmf<R (C::*)(Args...) const> : std::true_type{};

template<class C, class Fty, Fty F>
struct A{
  static_assert(std::is_const<C>() == is_ptcmf<Fty>(), "Must pair const with const.");
};

実例。

使用法は になりますA<foo, decltype(&foo::bar), &foo::bar>。冗長性があると思われる場合は同意しますが、それを取り除く良い方法はまだありません

于 2013-03-04T00:38:58.770 に答える
1

記録のために、これが私がそれを解決した方法です:

template <typename F, F ptr>
struct A;  // undefined

template <typename C, void (C::*F)()>
struct A<void (C::*)(), F> {};

template <typename C, void (C::*F)() const>
struct A<void (C::*)() const, F> {};

struct foo
{
    void bar() const {}
    typedef A<decltype(&foo::bar), &foo::bar> bar_type;

    void baz() {}
    typedef A<decltype(&foo::baz), &foo::baz> baz_type;
};

皆さんの洞察に感謝します!

于 2013-03-04T13:27:07.933 に答える