Select class 模板的成员类型基于模板类型?

Select member type of class template based on template type?

我有一个 class 模板,其中包含某种类型的成员。此类型是根据实例化模板时提供的类型确定的。它使用默认值(在下面的示例中为 double),除非 class 提供了覆盖。 类 用作模板类型可能会提供此覆盖 type(此处 "Two" 提供覆盖类型 "int")。如果 class 提供覆盖,则仅当 class 还设置了 UseOverride 标志时才应使用覆盖。如果标志不存在或为 false,则应使用默认值 "double"。

问题是如果模板类型不提供 "type",那么编译器会在下面的代码中给出错误。我怀疑我需要在这里使用 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'; 
}

您走在正确的轨道上,但您不需要单独检查 useOverridetype 是否存在。相反,您可以在同一个 sfinae class:

中进行两项检查
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 是非常规的,但由于我们已经在 T 中测试 type 成员,这可能会更清楚这是怎么回事。一旦您了解解决方案的工作原理,我建议您使用 type

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 compiler does generate error. How to avoid this?

只需使用以下 帮助程序延迟对 ::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