3

下面的代码片段演示了我想要实现的目标,即创建两个模板特化(嗯,这里是一个主模板和一个特化),一个用于非常量成员函数,一个用于 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

这不是(部分)专业化的工作方式。当您在特化中提供参数时,它必须匹配相应参数的种类。

您的主模板有一个指向非 const成员函数(PTNCMF) 参数的指针,需要一个此类模板参数。但是,您的部分特化将指向const成员函数(PTCMF) 的指针作为参数传递,从而造成不匹配。PTCMF 不能转换为 PTNCMF,因此部分特化无效。

解决问题就这么多。您需要将参数的类型与实际参数分开。一种方法如下,简单地断言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 回答
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 回答
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 回答