I have a base class like
template <int parameter>
class Base {
public:
virtual int getMaxParameter() = 0;
}
and I chose one of multiple derived classes like
template <int parameter>
class DerivedA : public Base<parameter>
{
public:
int getMaxParameter() { return 2; }
}
via
const int p = 3;
Base<p>* base;
switch (unreleated_input_int) {
case 1:
base = new DerivedA<p>(); break;
case 2:
base = new DerivedB<p>(); break;
// ...
}
Q: How can I make sure, that the template parameter of Base & Derived does not exceed the return value of getMaxParameter()?
I could do something like
DerivedA() {
if (parameter > getMaxParameter())
//...
}
but I don't want to write this in every derived class. Can I do something like this in Base? I can't call pure virtual functions, but is there another way?
I dont need the virtual function, it could be eg a member variable of Derived instead.
You could use static_assert
(a compile-time assertion) to make DerivedA<3>
(where the condition 3 < 2
is not met) fail compilation (if you like that):
template <int parameter>
class DerivedA : public Base<parameter>
{
static_assert(parameter < 2, "Parameter for DerivedA is too large!");
// ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// condition message in case of error
public:
};
This will give you a nice hint if you write DerivedA<3>
:
error: static asertion failed: Parameter for DerivedA is too large!
You could turn 2
into a constexpr
member. constexpr
is an indication that it's known during compile-time, which is required for static_assert
:
template <int parameter>
class DerivedA : public Base<parameter>
{
static constexpr int maxParameter = 2;
static_assert(parameter < maxParameter, "Parameter for DerivedA is too large!");
public:
};
If you dislike to have this code in each derived class, you can move it to Base
, which now takes two parameters: the actual parameter and the maximum value. It has the disadvantage that the error message can't include the derived class name, but I guess this is not very important:
template <int parameter, int maxParameter>
class Base
{
static_assert(parameter < maxParameter, "Parameter is too large!");
};
template <int parameter>
class DerivedA : public Base<parameter, 2>
{
};
If you don't like the second template parameter for the Base
class (like it is the problem in your added factory code in your question), you can move it to the Base
constructor. It's a bit tricky to invoke the templated constructor, but possible with the help of template type deduction and a dummy parameter :
template <int parameter>
class Base
{
public:
template <int maxParameter>
Base(std::integral_constant<int, maxParameter>) {
static_assert(parameter < maxParameter, "Parameter is too large!");
}
};
template <int parameter>
class DerivedA : public Base<parameter>
{
public:
DerivedA() : Base(std::integral_constant<int, 2>()) {
// ...
}
};
If you can't use a static_assert
at compile time because the return value of getMaxParameter
of your derived class is not known yet, you can use a factory...
#include <iostream>
template <int parameter>
struct Base {
void verify () {
if (parameter > this->getMaxParameter())
std::cout << "Bigger\n";
else
std::cout << "Smaller\n";
}
virtual int getMaxParameter() = 0;
};
template <int parameter>
struct Derived : public Base<parameter> {
virtual int getMaxParameter() { return 0; }
};
template <int parameter>
Base<parameter> * make_and_verify () {
Base<parameter> * result = new Derived<parameter>;
result->verify();
return result;
}
int main() {
Base<0> * foo = make_and_verify<0>();
Base<1> * bar = make_and_verify<1>();
return 0;
}
The class is created at compile time as a template instantiation.
The best you can do is a static_assert
is the value to be checked against is a constexpr :
template <int parameter>
class DerivedA : public Base<parameter>
{
public:
static_assert(parameter < 2, "wrong template parameter value");
int getMaxParameter() { return 2; }
};
Or, assuming you can make getMaxParameter
a constexpr
:
template <int parameter>
class DerivedA : public Base<parameter>
{
public:
constexpr int getMaxParameter() { return 2; }
static_assert(parameter < getMaxParameter(), "wrong template parameter");
};
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.