2013-03-04 58 views
3

以下代码片段演示了我想要实现的内容,即创建两个模板特化(好吧,这里是主模板和专业化),将使用一个用于非const成员函数,一个用于const成员函数:如何重写它使其符合C++标准

// 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,英特尔13.0和MSVC 2012,它失败使用锵3.3或科莫4.3.10.1进行编译。我相信克朗其实是对的。

如何重写此代码以使其符合标准(即与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

为什么不向我们展示编译错误?为什么不提供版本信息? – 2013-03-04 00:31:43

+0

*“无法编译”* ...带有错误信息? – 2013-03-04 00:31:54

+0

我添加了编译器版本和Clang错误消息。 – hkaiser 2013-03-04 00:35:18

回答

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; 
}; 
+0

专业化此刻不考虑原始功能类型。 – Xeo 2013-03-04 00:50:53

3

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

您的主模板有一个指针-TO-非const -member功能(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."); 
}; 

Live example.

用法是A<foo, decltype(&foo::bar), &foo::bar>。如果您认为有一些冗余,我同意,但there is no nice way yet to get rid of it

+1

这不能回答我的问题。我已经说过Clang是正确的,而且这个代码是不合格的。 – hkaiser 2013-03-04 00:41:09

+0

@hkaiser:完成。 – Xeo 2013-03-04 00:49:59

+0

@StephenLin:到目前为止,它看起来像他只是想确保然而这两个配对,如果这不正是他想要的东西,可以很容易地创建专业化的场景了它有一点'enable_if'魔法。 – Xeo 2013-03-04 00:53:29

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; 
}; 

感谢大家的见解!