以下代码片段演示了我想要实现的内容,即创建两个模板特化(嗯,这里是主模板和特化),一个用于非const成员函数,一个用于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)()>
^
答案 0 :(得分:3)
这不是(部分)专业化的工作方式。当您在特化中提供参数时,它必须匹配相应参数的类型。
您的主模板有一个指向非const -member-function (PTNCMF)参数的指针,期望这种模板参数。但是,您的部分特化会将指针指向 const -member-function (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>
。如果您认为存在一些冗余,我同意,但there is no nice way yet to get rid of it。
答案 1 :(得分: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;
};
答案 2 :(得分: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;
};
感谢大家的见解!