static_assert:派生“必须”中的某个函数隐藏了Base的类函数

时间:2019-05-15 08:38:15

标签: c++ function inheritance c++17 static-assert

我面临一个奇怪的罕见问题,我想隐藏基类的函数B::f1(int)

class B{
    public: void f1(int){}
    public: void f1(float){}
};
class C : public B{
    public: void f1(int){
        //static_assert(ASSERT_that_thisFunctionHidParentFunction,"");
        //some rare ugly hacky stuff
    }
    public: void f1(char){
        //static_assert(!ASSERT_that_thisFunctionHidParentFunction,"");
    }
};

一切正常;我只是担心可维护性。
我希望确保函数C::f1(int)始终隐藏B::f1(int)

如果B::f1(int)将来会更改签名(例如更改为B::f1(int,int)),
 我想要一些编译错误来通知程序员C::f1(int)也应更改为C::f1(int,int)

在现实世界中,我有问题的函数f1没有重载。
但是出于教育目的,我也想知道如果过载也要解决。 (即可选)

我喜欢在代码注释中使用ASSERT_that_thisFunctionHidParentFunction这样的可爱解决方案。
我不在乎宏。

我可怜的解决方案

我试图用typedef强制执行编译错误,但是在某些情况下它不会断言失败(MCVE-coliru),因为int会自动转换为B::f1(float)

class B{
    public: void f1(int,int){}
    public: void f1(float){}
};
class C : public B{
    public: void f1(int){
        using XXX=decltype(std::declval<B>().f1(std::declval<int>()));
        //static_assert(ASSERT_that_thisFunctionHidParentFunction,"");
    }
    public: void f1(char){
        //static_assert(!ASSERT_that_thisFunctionHidParentFunction,"");
    }
};
int main() {
   return 0;
}

2 个答案:

答案 0 :(得分:1)

您可以检查函数指针是否不同。

在MSVC 2019和Clang 8中,这对我有用,但是GCC拒绝它为“不是常量表达式”,因此可能需要其他内容或运行时断言。不确定哪种标准适用。

class B {
public:
    void f1(int) {}
    void f2(int) {}
    void f3(int) {}
    void f1(float) {}
};
class C : public B {
public:
    void f1(int) {}
    void f1(char) {}
    void f3(int) {}
};
static_assert(&B::f1 != &C::f1); // Won't work because of the overloading, can static_cast to get the overload you want
static_assert(static_cast<void(B:: *)(int)>(&B::f1) != static_cast<void(C:: *)(int)>(&C::f1));
static_assert(static_cast<void(B:: *)(int)>(&B::f2) != static_cast<void(C:: *)(int)>(&C::f2)); // static assertion failed
static_assert(&B::f3 != &C::f3); // passes, no static_cast as not overloaded

在以这种方式隐藏成员函数时要非常小心,因为基类是公共的,而方法不是虚的。可以轻松地对其进行强制转换,然后不调用派生函数。

C *c = ...;
B *b = c; // Implicit
b->f1(5); // Calls B::f1, not C::f1

如果可能的话,最好进行继承protectedprivate以避免意外转换。

答案 1 :(得分:0)

按照我对您问题的理解,似乎您想确保几个实现类符合某个非虚拟概​​念。

template <typename Candidate>
struct ShipConcept
{
    constexpr ShipConcept()
    {
        using ProtoFoo = void (Candidate::*)(int);
        (void)static_cast<ProtoFoo>(&Candidate::foo);

        // Other tests ...
    }
};


struct Ship_A
 : private ShipConcept<Ship_A>
{
    Ship_A()
    {
    }

    void foo(int, int);
    void foo(float);
    void foo(int);        // (1)
};

如果第(1)行不存在,则会出现编译时错误。