I have a class template that has members of some type. This type is determined based on the type that is provided when instantiating the template. It uses a default (double in the example below) unless an override is provided by that class. Classes used as template types may provide this override type
(here "Two" provides the override type "int"). If a class provides the override, the override should only be used if the class also sets the UseOverride flag. If flag is absent or false, default "double" should be used.
Problem is that if the template type does not provide the "type", then compiler gives error in below code. I suspect I need to use SFINAE here, but haven't been able to figure out a suitable approach for it, even after puzzling and browsing related questions for a good part of the afternoon.
How to define the EventType template so that it works as intended? I want to keep the EventType<T>
syntax.
#include <iostream>
struct One {
//This type is ignored, and double is used, because UseOverride = true is not specified:
using type = short;
};
struct Two {
static constexpr bool UseOverride = true;
using type = int;
};
struct Three {
static constexpr bool UseOverride = false;
//I don't want the compiler to complain that "type" is not available here (because it should default to double anyhow since
//the class instructs not to use the override). But compile does generate error.
//How to avoid this?
};
template <typename T, typename = void>
struct overrideInfoProvided : std::false_type {};
template <typename T>
struct overrideInfoProvided<T, decltype((void)T::UseOverride, void())> : std::true_type {};
template <typename T>
constexpr bool Override()
{
if constexpr (overrideInfoProvided<T>::value)
{
return T::UseOverride;
}
return false;
}
template<class T>
using EventType = typename std::conditional_t<Override<T>(), typename T::type, double>;
template <class T>
struct Test
{
typename EventType<T> member;
Test()
{
std::cout << member << std::endl;
}
};
int main()
{
Test<One>();
Test<Two>();
//Gives error:
//Test<Three>();// `type': is not a member of any direct or indirect base class of `three';
}