【问题标题】:std::conditional_t for class type vs non-class typestd::conditional_t 用于类类型与非类类型
【发布时间】:2021-10-07 07:17:40
【问题描述】:

如何解决这个问题:

template<class T>
struct ResultType
{
    using type = std::conditional_t<std::is_class_v<T>, typename T::result_type, void>;
};

如果 T 不是类类型,它不可能返回 void,而是:

错误:‘int’不是类、结构或联合类型 24 |使用 type = std::conditional_tstd::is_class_v;

所以我不需要尝试调用 false 表达式,但是如何调用呢?

【问题讨论】:

  • “所以我不需要尝试调用错误的表达式” -- 你的意思不是反过来吗?如果T 不是类类型,则失败应该在typename T::result_type;所以当条件为false 时,您不希望评估 true expressIon

标签: c++ typetraits


【解决方案1】:

如下:

using type = std::conditional_t<std::is_class_v<T>, typename T::result_type, void>;

T = int 时,typename T::result_type 部分将失败,因为typename int::result_type 格式不正确。

您可以通过使用模板特化而不是 std::conditional 来解决此问题,它执行完全相同的操作,但在 T 不是类类型时避免使用 T::result_type

#include <type_traits>

template <typename T, typename = void>
struct ResultType;

template <typename T>
struct ResultType<T, std::enable_if_t<!std::is_class_v<T>>> {
    using type = void;
};

template<typename T>
struct ResultType<T, std::enable_if_t<std::is_class_v<T>>> {
    using type = typename T::result_type;
};

// ...

struct X {
    using result_type = int;
};

int main() {
    static_assert(std::is_same_v<typename ResultType<X>::type, typename X::result_type>, "FAIL!");
    static_assert(std::is_same_v<typename ResultType<int>::type, void>, "FAIL!");
}

【讨论】:

    【解决方案2】:

    std::conditional_t 是在两种类型之间进行选择,但是当T = int 那么T::result_type 不是一个类型。您可以使用 sfinae:

    #include <type_traits>
    
    template <typename T, typename = void>
    struct result_type_or_void {
        using type = void;
    };
    template <typename T>
    struct result_type_or_void<T,std::void_t<typename T::result_type>> {
        using type = typename T::result_type;
    };
    
    template<class T>
    struct ResultType
    {
        using type = typename result_type_or_void<T>::type;
    };
    
    struct Test {
        using result_type = int;
    };
    
    int main() {
        ResultType<int> t;
        static_assert( std::is_same_v<ResultType<int>::type,void>);
        static_assert( std::is_same_v<ResultType<Test>::type,int>);
    }
    

    【讨论】:

    • 所以我不得不求助于 sfinae :-/
    【解决方案3】:

    失败是因为std::conditional 选择了两个类型表达式之一——但此时类型表达式已经被评估。由于int 不是一个类,并且没有result_type——它会出错。

    正如其他人指出的那样,这可以通过 enable_ifvoid_t 使用 SFINAE 解决——但另一种方法是利用表达式 SFINAE 的函数重载,而不是要求部分特化:

    template <typename T, typename Default = void>
    class ResultType
    {
        static auto test(...) -> Default;
        template <typename U>
        static auto test(const U&) -> typename U::result_type;
    public:
        using type = decltype(test(std::declval<T>()));
    };
    

    Live Example

    T 是定义result_type 的类型时,启用test(const U&amp;) 分支并选择用于重载解析;否则 test(...) 将被选中用于其他所有内容并变为 Default(在本例中为 void)。

    然后使用 decltype 通过评估表达式以查看选择了哪个重载来推断类型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-02
      • 1970-01-01
      • 1970-01-01
      • 2022-01-11
      • 2021-09-10
      相关资源
      最近更新 更多