根据模板类型选择类模板的成员类型?

时间:2020-06-04 15:24:12

标签: c++ templates sfinae

我有一个具有某些类型成员的类模板。此类型是根据实例化模板时提供的类型确定的。除非该类提供覆盖,否则它将使用默认值(在下面的示例中为双精度)。用作模板类型的类可以提供此覆盖[{'month': 'March', 'surname': 'john March'}, {'month': 'April', 'surname': "April O'Neil"}, {'month': 'May', 'surname': 'David May'}] (此处“ Two”提供覆盖类型“ int”)。如果类提供了覆盖,则仅当该类还设置UseOverride标志时才应使用覆盖。如果标志不存在或为false,则应使用默认的“ double”。

问题是,如果模板类型不提供“类型”,则编译器在以下代码中给出错误。我怀疑我需要在这里使用SFINAE,但即使在整个下午的大部分时间里困惑并浏览了相关问题之后,仍无法找到合适的方法。

如何定义EventType模板以使其按预期工作?我想保留type语法。

EventType<T>

2 个答案:

答案 0 :(得分:2)

我不想让编译器抱怨“ type”在这里不可用(因为无论如何它都应该默认为double,因为该类指示不要使用覆盖)。但是编译器确实会产生错误。如何避免这种情况?

只需使用下面的type_identity助手来延迟对::type的访问:

template <typename T>
struct type_identity { using type = T; };

template <typename T>
using EventType = typename std::conditional_t<Override<T>()
                                            , T
                                            , type_identity<double>>::type;
//                                            ~~~~~~~~~~~~^        

DEMO

答案 1 :(得分:1)

您处在正确的轨道上,但无需单独检查useOverridetype是否存在。相反,您可以在同一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