【问题标题】:Error storing instance of member function template存储成员函数模板的实例时出错
【发布时间】:2017-11-20 13:22:49
【问题描述】:

我正在尝试存储指向成员函数模板Derived::initialize 实例的指针,如下所示(另请参阅rextester.com。对于后代,我创建了一个simpler version 的问题。):

class Base
{
public:
    typedef void (Base::*setterFunction)( unsigned );

    template<unsigned N>
    struct SetterInterface
    {
        static Base::setterFunction Function;
    };

protected:
    template<unsigned N>
    void setterImpl( unsigned )
    {
    }
};

template<unsigned N>
Base::setterFunction Base::SetterInterface<N>::Function = &Base::setterImpl<N>;

class Derived : public Base
{
public: 
    typedef void (Derived::*Initializer)();

    template<typename T , void (T::*F)( unsigned ) >
    void initialize()
    {
    }

    template<typename C>
    Derived( C* )
    {
        Initializer initializer = &Derived::initialize<C, C::template SetterInterface<0>::Function>;    // NOT OK
        //Initializer initializer = &Derived::initialize<C, C::template setterImpl<0> >;    // OK
    }
};

int main()
{
    Derived derived( (Base*)0 );
}

但我在 GCC 5.4.0(和 6.4.0)上收到错误消息

Test.cpp: In instantiation of ‘Derived::Derived(C*) [with C = Base]’:
Test.cpp:45:28:   required from here
Test.cpp:37:39: error: no matches converting function ‘initialize’ to type ‘Derived::Initializer {aka void (class Derived::*)()}’
   Initializer initializer = &Derived::initialize<C, C::template SetterInterface<0>::Function>;
                                       ^
Test.cpp:30:7: note: candidate is: template<class T, void (T::* F1)(unsigned int)> void Derived::initialize()
  void initialize()

问题似乎出在成员函数模板参数上,因为C::template setterImpl&lt;0&gt; 有效,而C::template SetterInterface&lt;0&gt;::Function(我认为它是前者的别名)无效。例如:

Base::setterFunction f1 = &Base::setterImpl<0>;
Base::setterFunction f2 = Base::template SetterInterface<0>::Function;

【问题讨论】:

  • initialize() 非类型模板参数应该是常量表达式;在你的代码中它是一个静态成员,所以它不能工作;它可以,如果您将其声明为静态 constexpr;不管怎样,你想达到什么目的?

标签: c++ templates c++98 pointer-to-member


【解决方案1】:

问题是initialize()non-type-template-parameter应该是常量表达式;在你的代码中它是一个静态成员,所以它不能工作;它可以,如果你将它声明为 static constexpr (但你至少需要一个 C++11 编译器):

class Base
{
protected:
    template<unsigned N>
    void setterImpl( unsigned );
public:
    typedef void (Base::*setterFunction)( unsigned );

    template<unsigned N>
    struct SetterInterface
    {
        static constexpr Base::setterFunction Function = &Base::setterImpl<N>;
    };
};

【讨论】:

  • 不幸的是,我仅限于 C++98/03。我正在修改问题标签以表明这一点。
  • @olumide 实际上,你想要的在 c++03 中似乎是不可能的;说了这么多,为什么不直接传setterImpl呢?
  • 我不能,因为setterImplDerived 继承的其他基类(未显示)中有不同的名称。因此SetterInterface::Function 尝试为这些成员函数创建一个通用名称。
  • @olumide 你的意思是在真正的代码中 Derived 在它的基础上被模板化了吗?
  • 不,不是。它只是继承了一堆具有不同名称的setterImpl(我使用这个名称作为占位符)函数的派生类。而不是重命名所有这些setterImpls 和对它们的引用,我试图包装给所有这些成员函数一个本地别名。 .... 我想我可以创建每个类的包装函数来调用实现,但别名会更好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-26
  • 1970-01-01
  • 1970-01-01
  • 2021-10-26
  • 2012-05-09
  • 1970-01-01
相关资源
最近更新 更多