代码之家  ›  专栏  ›  技术社区  ›  DarthRubik

转换模板中的成员函数指针

  •  6
  • DarthRubik  · 技术社区  · 6 年前

    假设我有以下两个类:

    template<typename T>
    struct Base
    {
        void foo();
    };
    
    struct Derived : Base<Derived> {};
    

    void (Derived::*thing)() = &Derived::foo; 
    

    编译器很高兴(如我所料)。

    当我把它放在两个级别的模板中时,它突然爆炸了:

    template<typename T, T thing>
    struct bar {};
    
    template<typename T>
    void foo()
    {
        bar<void (T::*)(),&T::foo>{};
    }
    
    int main()
    {
        foo<Derived>();  // ERROR
        foo<Base<Derived>>(); // Works fine
    }
    

    non-type template argument of type 'void (Base<Derived>::*)()' cannot be converted to a value of type 'void (Derived::*)()'
    

    godbolt

    this 但我不能完全肯定。。。。

    3 回复  |  直到 6 年前
        1
  •  6
  •   Barry    6 年前

    @YSC 确定了 &Derived::foo;

    void (Derived::*thing)() = &Derived::foo; 
    

    2 非类型模板参数的模板参数应为 已转换模板参数类型的常量表达式。

    [表达式常量]

    4 T型转换常量表达式是一个表达式, 常量表达式和隐式转换序列只包含

    pointer to member conversions . 从而使模板参数对指定的参数无效。


    decltype(&T::foo) 而不是 void (T::*)() 作为类型参数。这是一个结构良好的替代品:

    bar<decltype(&T::foo), &T::foo>{};
    

        2
  •  4
  •   Community CDub    4 年前

    那是因为 &Derived::foo 实际上是一种 void (Base<Derived>::*)() :

    [expr.unary]/3

    一元运算符的结果是指向其操作数的指针。操作数应为左值或限定id。如果操作数是限定id,用类型T命名某个C类的非静态或变量成员m,则结果的类型指针指向类型T的C类成员,并且是指定C::m的prvalue。

    注意 ... 糟糕的措辞。

        3
  •  0
  •   Jonathan Mee    6 年前

    请注意,即使没有模板,这也是一个错误,例如,如果您的类不是模板:

    struct Base {
        void foo();
    };
    
    struct Derived : Base {};
    

    foo<Base>() : https://ideone.com/MQE0ff


    一个可能的替代解决方案是,首先是为了简化,而不是采用两个模板参数 bar 使用 auto 模板参数类型:

    template<auto thing>
    struct bar{};
    

    接下来我们需要实施 is_specialization_of

    template<template<typename...> class T, typename U>
    struct is_specialization_of : std::false_type {};
    
    template<template<typename...> class T, typename... Ts> 
    struct is_specialization_of<T, T<Ts...>> : std::true_type {};
    

    现在我们可以重写了 foo 使用 是的 Base 底座 专业化。)

    template<typename T>
    void foo()
    {
        conditional_t<is_specialization_of<Base, T>::value, bar<&T::foo>, bar<&Base<T>::foo>>{};
    }
    

    thing 酒吧 另外还采纳了我的建议。您可以在这里查看: https://coliru.stacked-crooked.com/a/2a33b8bd38896ff5