我有一个具有某些类型成员的类模板。此类型是根据实例化模板时提供的类型确定的。除非该类提供覆盖,否则它将使用默认值(在下面的示例中为双精度)。用作模板类型的类可以提供此覆盖type
(此处“ Two”提供覆盖类型“ int”)。如果一个类提供了覆盖,则仅当该类还设置了UseOverride标志时才应使用覆盖。如果标志不存在或为false,则应使用默认的“ double”。
问题是,如果模板类型不提供“类型”,则编译器在以下代码中给出错误。我怀疑我需要在这里使用SFINAE,但即使在整个下午的大部分时间里都困惑并浏览了相关问题之后,仍无法找到合适的方法。
如何定义EventType模板以使其按预期工作?我想保留EventType<T>
语法。
#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';
}
您处在正确的轨道上,但是您无需单独检查useOverride
和type
是否存在。相反,您可以在同一sfinae类中进行两项检查:
template <typename T, typename = void, typename = void>
struct EventType_T {
using t = double; // default if useOverride or type doesn't exist
};
template <typename T>
struct EventType_T<T, std::void_t<decltype(T::UseOverride)>,
std::void_t<typename T::type>> {
// choose type if useOverride is true, and double otherwise
using t = std::conditional_t<T::UseOverride, typename T::type, double>;
};
template <typename T>
using EventType = typename EventType_T<T>::t;
这里是demo。这样,您仍然可以像以前一样使用EventType<T>
语法。
注意,t
成员而不是type
是非常规的,但是由于我们已经在type
中测试了T
成员,因此这可能使事情更加清楚。一旦您了解解决方案的工作原理,我建议使用type
。