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

问题描述 投票:1回答:1

我有一个具有某些类型成员的类模板。此类型是根据实例化模板时提供的类型确定的。除非该类提供覆盖,否则它将使用默认值(在下面的示例中为双精度)。用作模板类型的类可以提供此覆盖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'; 
}
c++ templates sfinae
1个回答
0
投票

您处在正确的轨道上,但是您无需单独检查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

© www.soinside.com 2019 - 2024. All rights reserved.