【问题标题】:Does there exist a lazy equivalent of std::conditional in C++?C++ 中是否存在 std::conditional 的惰性等效项?
【发布时间】:2020-07-05 21:57:20
【问题描述】:

在调用std::contional<bool, T1, T2> 时,T1 和 T2 类型都会在调用时立即实例化,无论 bool 的值如何,是否存在仅实例化相关类型的实现(或一些实现它的指针) .

例如以下代码是不可能使用 std::conditional 编写的。我们甚至不能在结构上使用 SFINAE(参见示例)。

struct Term {};

template <int N, typename T, typename ...Ts>
struct PairList
{
    static constexpr int i = N;
    using type = T;
    using tail = PairList<N + 1, Ts...>;
};

template <int N, typename T>
struct PairList<N, T>
{
    static constexpr int i = N;
    using type = T;
    using tail = Term;
};


template <int N, typename pairList>
struct get
{
    static constexpr auto good = (N == pairList::i);
    using T =  typename std::conditional<
                   good,
                   typename pairList::type,
                   typename get<N, typename pairList::tail>::T>::type;  // The second parameter might not be defined
};

【问题讨论】:

  • conditional&lt;A,B::type,C::type&gt; 替换为conditional&lt;A,B,C&gt;::type

标签: c++ stl c++17 template-meta-programming sfinae


【解决方案1】:

您可以使用if constexpr 懒惰地实例化模板,同时保持熟悉的代码结构:

// C++20: std::type_identity
template<typename T>
struct type_t {
    using type = T;
};

template <int N, typename pairList>
struct get
{
    static auto choose_type() {
        if constexpr (N == pairList::i) {
            return type_t<typename pairList::type>{};
        } else {
            return type_t<typename get<N, typename pairList::tail>::T>{};
        }
    }

    using T = typename decltype(choose_type())::type;
};

【讨论】:

    【解决方案2】:

    我通常使用模板特化来避免这类问题

    // bool is false -> recursion
    template <int N, typename pairList, bool = N == pairList::i>
    struct get : public get<N, typename pairList::tail>
     { };
    
    // bool is true -> stop recursion and type is selected
    template <int N, typename pairList>
    struct get<N, pairList, true>
     { using T = typename pairList::type; };
    

    以下是完整的编译示例

    #include <type_traits>
    
    struct Term {};
    
    template <int N, typename T, typename ...Ts>
    struct PairList
    {
        static constexpr int i = N;
        using type = T;
        using tail = PairList<N + 1, Ts...>;
    };
    
    template <int N, typename T>
    struct PairList<N, T>
    {
        static constexpr int i = N;
        using type = T;
        using tail = Term;
    };
    
    // bool is false -> recursion
    template <int N, typename pairList, bool = N == pairList::i>
    struct get : public get<N, typename pairList::tail>
     { };
    
    // bool is true -> stop recursion and type is selected
    template <int N, typename pairList>
    struct get<N, pairList, true>
     { using T = typename pairList::type; };
    
    
    int main ()
     {
       using T0 = PairList<0u, int, long, long long>;
       using T1 = get<1u, T0>::T;
    
       static_assert( std::is_same_v<T1, long>, "!" );
     }
    

    【讨论】:

      猜你喜欢
      • 2020-02-07
      • 1970-01-01
      • 2017-09-07
      • 2023-03-14
      • 1970-01-01
      • 1970-01-01
      • 2012-06-17
      • 2021-12-03
      • 2011-03-20
      相关资源
      最近更新 更多