如何为 dynamic_cast 指定“所有参数化类型”或“所有参数列表”?

How to specify “all parameterized types” or “all argument lists” for a dynamic_cast?

我正在尝试调用派生 class 上的方法。派生的 class 有模板参数,但我不知道它们是什么。如何为 dynamic_cast 指定“所有参数化类型”或“所有参数列表”?

下面是 MCVE,但这里是问题的主旨:

// Contrived, but close approximation
DerivedOne<X> one;
// Another one
DerivedTwo<X,Y> two;
// Maybe another one somewhere...
DerivedTwo<X,Z> three;

// Here's the problem
Base& base = dynamic_cast<Base&>(two);
if (base.HasOp())
{
    // By the time we get back to its a "DerivedTwo", we don't know
    // or care what the template parameters are. All we know is it has
    // the DoOp() method and we want to call it.
    DerivedTwo& derived = dynamic_cast<DerivedTwo&>(base);
    derived.DoOp();
}

MCVE 并没有我想要的那么小,但是有一些移动的部分需要建模。还需要维护 ABI,我怀疑它造成了相当大的痛苦。


示例程序

// Base interface/contract
struct Base {
    virtual bool HasOp() const {
        return false;
    }
};

// structs to use a template parameters for derived classes
struct X {}; struct Y {}; struct Z {};

// First derived class with first requirement
template <class One>
struct DerivedOne : public Base {
    // Does not have DoOp()
};

// Second derived class with second requirement
template <class One, class Two>
struct DerivedTwo : public Base {
    virtual bool HasOp() const {
        return true;
    }
    virtual void DoOp() const {
        // ...
    }
};

int main(int argc, char* argv[])
{
    // Contrived, but close approximation
    DerivedTwo<X,Y> two;
    // Maybe another one somewhere...
    DerivedTwo<X,Z> three;

    // Here's the problem
    Base& base = dynamic_cast<Base&>(two);
    if (base.HasOp())
    {
        // By the time we get back to its a "DerivedTwo", we don't know
        // or care what the template parameters are. All we know is it has
        // the DoOp() method and we want to call it.
        DerivedTwo& derived = dynamic_cast<DerivedTwo&>(base);
        derived.DoOp();
    }

    return 0;
}

编译结果

C:\test>cl.exe /TP test.cxx
Microsoft (R) C/C++ Optimizing Compiler Version 17.00.61030 for x86

test.cxx
test.cxx(42) : error C2955: 'DerivedTwo' : use of class template requires template argument list
        test.cxx(19) : see declaration of 'DerivedTwo'
test.cxx(45) : error C2662: 'DerivedTwo<One,Two>::DoOp' : cannot convert 'this' pointer from 'DerivedTwo' to 'const DerivedTwo<One,Two> &'
        Reason: cannot convert from 'DerivedTwo' to 'const DerivedTwo<One,Two>'
        Conversion requires a second user-defined-conversion operator or constructor

如果我将问题行更改为:

DerivedTwo<>& derived = dynamic_cast<DerivedTwo<>&>(base);

然后结果:

test.cxx
test.cxx(44) : error C2976: 'DerivedTwo' : too few template arguments
        test.cxx(19) : see declaration of 'DerivedTwo'
        test.cxx(19) : see declaration of 'DerivedTwo'
test.cxx(45) : error C2662: 'DerivedTwo<One,Two>::DoOp' : cannot convert 'this' pointer from 'DerivedTwo' to 'const DerivedTwo<One,Two> &'
        Reason: cannot convert from 'DerivedTwo' to 'const DerivedTwo<One,Two>'
        Conversion requires a second user-defined-conversion operator or constructor

好像编译器强迫我进行专业化,而不是允许调用每个 DerivedTwo class 中存在的方法。这就是我寻找“所有参数列表”(而不是专业化)的方式的原因。


如果有帮助,真实世界的代码会创建数字签名。除了一个需要随机值 k 之外,所有受支持的签名方案。基础 class 具有创建随机 k 的代码。确定性签名需要非随机 k,我们正在尝试捕获它。 DoOp 正在尝试为确定性过程获取非随机 k

你不能为所欲为。

尝试不同的计划。

我的建议是另一种虚方法。如果可以完成,此方法将执行您想要的任务,否则将失败。如果有两种方法可以做到,而不是失败你做任何有效的方法。