问题
I'm trying to call a method on a derived class. The derived class has template parameters, but I don't know what they are. How do specify “all parameterized types” or “all argument lists” for a dynamic_cast
?
Below is the MCVE, but here's the thrust of the problem:
// 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();
}
The MCVE is not as minimal as I would like, but there's a few moving pieces that need to be modeled. There's also a requirement to maintain an ABI, and I suspect its responsible for a fair amount of the pain.
Example Program
// 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;
}
Compile Result
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
If I change the problem line to:
DerivedTwo<>& derived = dynamic_cast<DerivedTwo<>&>(base);
Then it results:
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
Its as if the compiler is forcing me into a specialization, rather than allowing the call to the method that's present in every DerivedTwo
class. Its the reason I am looking for the way to say “all argument lists” (rather than a specialization).
If it helps, the real world code creates a digital signature. All supported signature schemes except one require a random value k
. The base class has the code to create a random k
. Deterministic signatures require a non-random k
, and we are trying to capture it. The DoOp
is trying to get the non-random k
for the deterministic process.
回答1:
You cannot do what you want to.
Try a different plan.
My suggestion is another virtual method. This method does the task you want if it can be done, and fails otherwise. If there are two ways to do it, instead of failing you do whatever way works.
来源:https://stackoverflow.com/questions/41049526/how-to-specify-all-parameterized-types-or-all-argument-lists-for-a-dynamic-c