Reputation: 53
My situation is similar to the one described here: conditional (SFINAE) override.
Except in that question, there is only one function being conditionally overridden. I am wondering how I can get a solution that would enable this for n independent functions. For the answer described in the linked question, this would result in n^2 versions (true/false combinations) of the class.
#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;
}
However, g++-8.1.0 does not appear to generate symbols for the overridden methods and calls 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 complains with:
error: only virtual member functions can be marked 'override'
They fixed a very similar bug: https://bugs.llvm.org/show_bug.cgi?id=13499. Ok, so I try without the override keyword and get the same result as 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()
Both compilers failing to accomplish the task at runtime leads me to believe that I am doing something wrong with my example, or there is a rule that I am trying to break. Please enlighten me.
The goal is to have something that can override any combination of virtual methods in the base class without creating a "version" for each combination. Note: this should be done during compile-time.
Upvotes: 3
Views: 131
Reputation: 66230
The problem is that a template function can't be a virtual
one.
The best alternative that come in my mind is the creation of a oFoo
template struct, with specialization, to override (or not) foo()
according a boolean template value
template <bool>
struct oFoo : virtual public A
{ void foo () override { std::cout << "B::foo()" << std::endl; } };
template <>
struct oFoo<false>
{ };
then a oBar
template struct for the same for bar()
template <bool>
struct oBar : virtual public A
{ void bar () override { std::cout << "B::bar()" << std::endl; } };
template <>
struct oBar<false>
{ };
so you can write B
simply as follows
template <bool FOO, bool BAR>
struct B : virtual public A, public oFoo<FOO>, public oBar<BAR>
{ };
Observe the virtual
inheritance to avoid the diamond problem.
The following is a full compiling example
#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();
}
Upvotes: 2