可扩展的SFINAE条件覆盖

问题描述 投票:2回答:1

Context

我的情况类似于这里描述的情况:conditional (SFINAE) override

除了那个问题,只有一个函数被有条件地覆盖。我想知道我如何能够获得一个能够为n个独立函数启用此解决方案的解决方案。对于链接问题中描述的答案,这将导致该类的n ^ 2个版本(真/假组合)。

Attempt

#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。好的,所以我尝试没有override关键字,并获得与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()

两个编译器都无法在运行时完成任务,这让我相信我的例子我做错了,或者我有一条规则试图打破。请赐教。

Goal

目标是拥有可以覆盖基类中任何虚拟方法组合的东西,而无需为每个组合创建“版本”。注意:这应该在编译期间完成。

c++ c++11 override sfinae virtual-method
1个回答
2
投票

问题是模板功能不能是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();
 }
© www.soinside.com 2019 - 2024. All rights reserved.