Problem
I would like to detect if a class has member variables and fail a static assert if they do. Something like:
struct b {
int a;
}
static_assert(!has_member_variables<b>, "Class should not contain members"). // Error.
struct c {
virtual void a() {}
void other() {}
}
static_assert(!has_member_variables<c>, "Class should not contain members"). // Fine.
struct d : c {
}
static_assert(!has_member_variables<d>, "Class should not contain members"). // Fine.
struct e : b {
}
static_assert(!has_member_variables<e>, "Class should not contain members"). // Error.
struct f : c {
char z;
}
static_assert(!has_member_variables<f>, "Class should not contain members"). // Error.
Is there a way to achieve this with SFINAE template? This class may have inheritance or even multiple inheritance with virtual functions (no members in the base classes though).
Motivation
I have a pretty simple setup as follows:
class iFuncRtn {
virtual Status runFunc(Data &data) = 0;
};
template <TRoutine, TSpecialDataType>
class FuncRoutineDataHelper : public iFuncRtn {
Status runFunc(Data &data) {
static_assert(!has_member_variables<TRoutine>, "Routines shouldnt have data members!");
// Prepare special data for routine
TSpecialDataType sData(data);
runFuncImpl(sData);
}
class SpecificRtn :
public FuncRoutineDataHelper<SpecificRtn, MySpecialData> {
virtual Status runFuncImpl(MySpecialData &sData) {
// Calculate based on input
sData.setValue(someCalculation);
}
};
The FunctionalityRoutine
s are managed and run on a per tick basis. They are customized and can perform a wide variety of tasks such as contacting other devices etc. The data that is passed in can be manipulated by the routine and is guaranteed to be passed in on each tick execution until the functionality is finished. The right type of data is passed in based on the DataHelper
class. I wan't to discourage future people from mistakenly adding data to the functionality routines as it is very unlikely to do what they expect. To force this, I was hoping to find a way with static assert.
std::is_empty
if the base classes are also expected to be empty. Otherwise, there is no way in current C++. – Stokestd::is_empty
will detect my virtual members so I can't use this. The Motivation part should have made this clear. – HeredityTRoutine
and aTSpecialDataType
. and part of the contract you want is thatTRoutine
can't have any data members. ThereforeTRoutine
only encapsulates a routine. Can you rework this where instead of a class, the first template parameter is astd::function<>
type? That'd enforce what you want without question. – HampshireStatus(*)(Data&)
? That is the C++ signature of some stateless callable with aData&
which returns aStatus
. – Maighdilnstatic_assert
then it will be a much stronger assurance for people to do the right thing. Enforcement of coding policy throughstatic_assert
is one of its massive advantages. – Hereditystatic_assert
and template type assertion are part of c++? I don't get your meaning about making c++ a different language ... – Hereditystatic_assert
provides. It means you can turn hard to find run-time errors due to design mis-use into obvious compile time failures. – Hereditystatic_assert
sometimes. But I also pick my battles! And I tend only to use it for diagnostic purposes (as in, "this check is here because you can't do what you're trying to do, with my design, and this assert makes it easier to spot that") not social purposes (as in, "this check is here because I don't want you to do what you're trying to do as it may -- but may not -- cause you problems later). Certainly YMMV and I have no problem with your question per se. – Tweeter