【问题标题】:Using class member pointers in nested templates gives GCC error "mismatched types Child and Base"在嵌套模板中使用类成员指针会导致 GCC 错误“子类型和基类型不匹配”
【发布时间】:2026-02-14 23:00:02
【问题描述】:

关于一种复古环境的奇怪问题。我在 gnu++11 模式下使用 GCC 4.8.2 对给定库进行编码。 该库有这样的接口代码:

template<class somecls>
class LibraryInterface
{
public:
    template<class var>
    void someFunc(somecls *obj, var somecls::* member)
    {
        std::cout << "doing some nice computations on [" << obj->*member << "] ..." << std::endl;
    }
};

这样的代码可以很好地工作:

class Base1
{
public:
    std::string member1;
};

int main()
{
        LibraryInterface<Base1> lib_if;
        Base1 my_var;
        my_var.member1 = "data1";
        lib_if.someFunc(&my_var, &Base1::member1);
}

但是当事情变得更复杂时,我想使用一个派生自其他两个具有所需成员的类的类。基类被拆分是因为(在其他一些用例中)还需要单独使用这两个基类。所以我最终得到了这样的结果:

class Base1
{
public:
    std::string member1;
};

class Base2
{
public:
    std::string member2;
};

class Child : public Base1, public Base2
{
    // just a class which holds members of both base classes
};

int main()
{
    LibraryInterface<Child> lib_if;
    Child my_var;
    my_var.member1 = "data1";
    my_var.member2 = "data2";
    lib_if.someFunc(&my_var, &Child::member2);
}

但是,GCC 不喜欢这样并给了我以下信息:

template.cpp: In function 'int main()':
template.cpp:37:42: error: no matching function for call to 'LibraryInterface<Child>::someFunc(Child*, std::string Base2::*)'
  lib_if.someFunc(&my_var, &Child::member2);
                                          ^
template.cpp:37:42: note: candidate is:
template.cpp:8:7: note: template<class var> void LibraryInterface<somecls>::someFunc(somecls*, var somecls::*) [with var = var; somecls = Child]
  void someFunc(somecls *obj, var somecls::* member)
       ^
template.cpp:8:7: note:   template argument deduction/substitution failed:
template.cpp:37:42: note:   mismatched types 'Child' and 'Base2'
  lib_if.someFunc(&my_var, &Child::member2);

当然,我总是可以只创建第三个类,然后将 Base1 和 Base2 中的所有成员复制并粘贴到其中,但我希望保持整洁。拥有类层次结构将带来自动拥有基类的新成员而无需再次复制和粘贴(呃!)的好处。

我真的不知道在这里做什么。当前的 MSVC 可以使用该代码,但即使 GCC 9.3.0 也会出现与 GCC 4.8.2 相同的错误。 不可能更改库代码 - 这是给定的。如果有帮助的话,我当然可以重写我自己的(非模板)代码。 也许有一些 cmdline 标志可以说服 GCC 接受这段代码?

提前感谢您的任何提示!

【问题讨论】:

    标签: c++ templates gcc


    【解决方案1】:

    这是您的解决方案。它适用于 GCC、CLang 和 MSVC。

    int main()
    {
        LibraryInterface<Child> lib_if;
        Child my_var;
        my_var.member1 = "data1";
        my_var.member2 = "data2";
    
        lib_if.someFunc(&my_var,  static_cast<std::string Child::*>(&Child::member2));
    }
    

    标准规定,成员地址表达式的类型是指向声明该成员的类的成员的指针,而不是指向限定id中的类成员的指针。

    这个链接很好地描述了这个问题:http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3772.pdf

    【讨论】:

    • 哇。我很尴尬,我自己没有想出一个简单的 static_cast 。感谢您的快速回答和解释性链接!这确实解决了我的问题。