масштабируемое условное переопределение SFINAE - PullRequest
2 голосов
/ 09 марта 2019

Контекст

Моя ситуация похожа на описанную здесь: условное (SFINAE) переопределение .

За исключением этого вопроса, только одна функция может быть переопределена. Мне интересно, как я могу получить решение, которое позволило бы это для n независимых функций. Для ответа, описанного в связанном вопросе, это приведет к n ^ 2 версиям (комбинации истина / ложь) класса.

1009 * Покушение * #include <cstdio> #include <type_traits> struct A { virtual void foo() { printf("A::foo()\n"); } virtual void bar() { printf("A::bar()\n"); } void print() { foo(); bar(); } }; template <bool FOO, bool BAR> struct B : public A { template <bool b = FOO> typename std::enable_if<b, void>::type foo() override { printf("B::foo()\n"); } template <bool b = BAR> typename std::enable_if<b, void>::type bar() override { printf("B::bar()\n"); } }; int main() { A *a = new B<true, false>(); a->print(); return 0; } Однако g ++ - 8.1.0 не генерирует символы для переопределенных методов и вызовов A::{foo,bar}(): $ g++ -std=c++11 test.cc && ./a.out && nm -C a.out | grep -e foo -e bar A::foo() A::bar() 00000000004006de W A::bar() 00000000004006c4 W A::foo() clang ++ - 6.0 жалуется на: error: only virtual member functions can be marked 'override' Они исправили очень похожую ошибку: https://bugs.llvm.org/show_bug.cgi?id=13499. Хорошо, поэтому я пытаюсь без ключевого слова переопределения и получаю тот же результат, что и g ++: $ clang++ -std=c++11 test.cc && ./a.out && nm -C a.out | grep -e foo -e bar A::foo() A::bar() 0000000000400850 W A::bar() 0000000000400820 W A::foo() Оба компилятора, не выполняющие задачу во время выполнения, заставляют меня поверить, что я делаю что-то не так с моим примером, или есть правило, которое я пытаюсь нарушить. Пожалуйста, просветите меня. Цель

Цель состоит в том, чтобы иметь что-то, что может переопределить любую комбинацию виртуальных методов в базовом классе, не создавая "версию" для каждой комбинации. Примечание: это должно быть сделано во время компиляции.

1 Ответ

2 голосов
/ 09 марта 2019

Проблема в том, что шаблонная функция не может быть virtual.

Лучшая альтернатива, которая приходит мне в голову, - это создание шаблонной структуры oFoo со специализацией для переопределения (или нет) foo() в соответствии с логическим значением шаблона

template <bool>
struct oFoo : virtual public A
 { void foo () override { std::cout << "B::foo()" << std::endl; } };

template <>
struct oFoo<false>
 { };

затем шаблон структуры oBar для того же самого для bar()

template <bool>
struct oBar : virtual public A
 { void bar () override { std::cout << "B::bar()" << std::endl; } };

template <>
struct oBar<false>
 { };

чтобы вы могли написать B просто следующим образом

template <bool FOO, bool BAR>
struct B : virtual public A, public oFoo<FOO>, public oBar<BAR>
 { };

Соблюдайте наследование virtual, чтобы избежать проблемы с алмазом.

Ниже приведен полный пример компиляции

#include <iostream>
#include <type_traits>                                                             
struct A
 {                                                                         
   virtual void foo() { std::cout << "A::foo()" << std::endl; }
   virtual void bar() { std::cout << "A::bar()" << std::endl; }
   void print() { foo(); bar(); }
 };

template <bool>
struct oFoo : virtual public A
 { void foo () override { std::cout << "B::foo()" << std::endl; } };

template <>
struct oFoo<false>
 { };

template <bool>
struct oBar : virtual public A
 { void bar () override { std::cout << "B::bar()" << std::endl; } };

template <>
struct oBar<false>
 { };

template <bool FOO, bool BAR>
struct B : virtual public A, public oFoo<FOO>, public oBar<BAR>
 { };

int main ()
 {
   A *a = new B<true, false>();

   a->print();
 }
...