Reputation: 53337
Suppose I have a struct for data:
struct TestData {
}
and a class with a member variable:
class TestContainer {
private:
TestData data;
};
Both are defined in a cpp file from a macro that is used in multiple test files.
Now I want to remove the data member at compile time if there is no TestData struct defined. If a test doesn't need data then there's no need to define the data member (and it would produce a warning for not being used). I thought of using std::enable_if
but failed to come up with a condition. Another approach would be to define a base template class and specializations as shown in this question, but how to specialize on the existence of a type?
How can this be done?
Upvotes: 1
Views: 2819
Reputation: 41780
You can check if a struct exist or not if you consider a forward declaration is not existing.
This example assume that either TestData
is always defined or never defined:
#include <type_traits>
// Comment this line to trigger the static assert
struct TestData {};
template<typename, typename = void>
struct MaybeData {};
template<typename T>
struct MaybeData<T, std::void_t<decltype(sizeof(T))>> {
T data;
};
struct TestContainer : MaybeData<struct TestData> {};
We can test our solution like this:
template<typename, typename = void>
constexpr auto has_data = false;
template<typename T>
constexpr auto has_data<T, std::void_t<decltype(T::data)>> = true;
static_assert(has_data<TestContainer>);
The mechanism behind this is instead of sending the struct itself (TestData
) as a type, we are using struct TestData
as an argument, which refers to the type if it exist, but forward declare it if not.
Then, we use sfinae to check if sizeof(T)
is a valid expression. If TestData
is an imcomplete type, the expression is not valid.
However, if the completeness of a type changes between instantiation of the template, the program is ill formed.
Upvotes: 3