Использование указателей на члены класса во вложенных шаблонах приводит к ошибке G CC «несовпадающие типы Child и Base» - PullRequest
2 голосов
/ 03 августа 2020

Странная проблема в стиле ретро. Я кодирую данную библиотеку с G CC 4.8.2 в режиме GNU ++ 11. В библиотеке есть такой интерфейсный код:

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

Однако G CC это не нравится и дает мне следующее:

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, но я бы хотел, чтобы все было аккуратно и аккуратно. Наличие иерархии классов дало бы преимущество автоматического создания новых членов базовых классов без необходимости повторного копирования и вставки (ура!).

Я действительно не знаю, что здесь делать. Текущий MSV C подходит для этого кода, но даже G CC 9.3.0 дает те же ошибки, что и G CC 4.8.2. Изменить код библиотеки нет возможности - это данность. Конечно, я мог бы переписать свой собственный (не шаблонный) код, если бы это помогло. Может быть, есть какой-то флаг cmdline, который убеждает G CC принять этот фрагмент кода?

Заранее спасибо за любые подсказки!

1 Ответ

2 голосов
/ 03 августа 2020

Вот тебе решение. Он работает с G CC, CLang и MSV C.

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

Стандарт утверждает, что тип выражения address-of-member является указателем на член класса, который объявляет член, а не указатель на член класса в квалифицированном идентификаторе.

Проблема очень хорошо описана в этой ссылке: http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3772.pdf

...